Users in the applications have permissions based on the groups they are in
We would like to store the list of groups a user is in, in the JWT token
When a user gets added or removed from the groups, that effectively means the permissions change and this is what should happen at the user's end:
If they have been removed entirely from the system, the user immediately is kicked back out to the login screen
If they have just been removed from a group, for example, the user is not kicked out
They are notified that their rights have been updated, they are told to please refresh the page
when the user refreshes, they stay on the page they are looking at
If the user is on a screen they no longer have access to, they are sent to the home page
1. We have so far been writing REST APIs that are all stateless but this seems to break that. What is the best way to achieve it?
2. If we were to keep it simple and ensure statelessness, What's the best approach?
With stateless authentication your ID token which contains your group information, isn't renewed until it expires (usually an hour). You can reduce this duration to 5 minutes. This would be the simplest way to make sure any update to group is reflected on the front end quickly. These tokens are independent and cannot be revoked once they are issued. Even if you run the global sign out API call or the forget device API call, only the refresh token is revoked, while the ID and access tokens are still valid until they expire.
The requirements you mention aren't compatible with a stateless authentication method. Sure, you can create a "hacky" flow where you have a database that records the id of users who are kicked out and before every call it checks the database but it would be a lot of unnecessary work and you would be defeating the whole point of using stateless authentication.
My suggestion, if you want to keep using cognito, is to reduce the expiration time of all tokens to the minumum. You can also eliminate refresh tokens from your flow but that would mean user needs to sign in every 5 minutes.
But if you really need to implement this, I would suggest using stateful authentication methods.
Last year I was building an application to create my own YT dashboard.
It was based only the code of a tutorial
They basically authenticate a user via OAuth and send requests to get channel data or playlists of the authenticated user.
I was trying out both the original tutorial app and my own (after a few dormant months) and they suddenly don't work anymore.
Meaning: I can authenticate on both, but on the original version I get a 403 error telling me: "The request is missing a valid API key." (on requesting channel data)
This is confusing because the API key is never used because only the OAuth client id was necessary.
And on my own fancy version, I get a 403 error telling me that I've exceeded my getting started quota. (on requesting the users playlists)
Looking at my quota page:
I can see, that queries per day (why is it there twice?) is somehow set to 0.
Perhaps creating a new OAuth 2.0 Client ID or a new API key would solve these errors, as was suggested in another post.
But since I'm planning to use the YT Data API in a real project soon and want to prevent this from ever happening I would like to understand what was going on. Why the daily quota limit is suddenly turned to 0 and how to go about it when that happens.
Or at least how to contact google about it.
Perhaps some of you have some insights.
UPDATE:
I've just found this post reporting, that after 90 inactive days, the quota is automatically set to 0.
Now I created a new OAuth Client Id and replaced the constant in my code. Nothing changed so far. Perhaps I have to wait 24h. Or perhaps I have to fill out this form which apparently can lead to months of back and forth email nonsense. I sure hope not.
It seemed the only viable option was to create a new project with new credentials.
(And one should not forget that the YT Data API has to be enabled again for the new project.)
Conceptually, I really like JWT as it is in line with the statelessness of REST etc (no state saved server-side, all relevant data is contained in the token).
What I am unsure about: how would you handle token expiry when not connected (ie, a "remember me" functionality)?
There's an emerging coverage of JWT on the web, but I couldn't find anyone that answered the expiry question yet.
Clarification: I am not asking how to handle a token soon-to-expire, but what to do when a token has already expired (user closed website/app for a while). The simplest solution that comes to my mind is caching the user's credentials, which is rather insecure.
There isn't a black and white answer to the given problem of how to implement the remember-me functionality theoretical wise. Lots of theoretical arguments are given on why something should not be done, while at the same time there is no clear answer given to the problem as for how it should practically be done.
Remember-me implicitly comes with the problem that you need a longer time window of token expiration, there is just no way around this. The most secure way is to have the user login regularly given brief expiry; nobody practically likes this though, so a tradeoff is made where theoretical secure perfection is weighed against practical measures.
The way this tradeoff works is by patching the imperfections that come with having a long expiry for a token. But make no mistake about it, you will need a jwt / cookie with long expiry (whether you use two tokens, implement some secondary refreshing mechanism or whatever, at the end you run into the same problem)!
Based on articles I've read on how others did it, this is how it's done.
The way I will implement this is by offering a 3-month expiry on a jwt stored in an httpOnly / secure cookie when the user checks remember-me.
On logout just clear the cookie.
Obviously protect using https / CSRF measures on top.
If you don't agree with it, stop fussing and offer an alternative solution - which there clearly isn't from the infinite number of discussions I've read on it.
If there were a straightforward solution to the problem, there probably wouldn't be so many discussions about it in the first place.
Edit:
You can use a refresh token mechanism, but it only works if you verify the time intervals when the refresh token gets used. For example, depending on the lifetime of the access token, you can govern how often you allow a user to refresh the token. If the intervals show suspicious activity, you should revoke both the tokens for all clients.
The problem revolves around the idea that either access token or refresh token would theoretically be stolen. So merely having a refreshing mechanism without additional security is essentially useless. If you can steal an access token, you can steal a refresh token too.
I am not so sure if I follow but I will write what I think.
Imagine the token as a hotel card, you pay in advance for 5 days (remember me set to expire on 5 days). I can enter the building, garage, room, etc. within those 5 days, after those 5 days, it won't work anymore.
What to do when token has already expired? Nothing at all.
Imagine I pay those 5 days and meh, I had an urgency and I go back home (with the card on the pocket). The hotel doesn't care at all, when the 5 days pass, the card is just an useless piece of plastic and if you try to use it on the hotel, it will do nothing.
So back to web development. If you offer a remember me service, you can put an expiry date to let's say 7 days. As long as the user has the token, he can access the service without any problem. If he loses the token, he needs to login again. If he uses the token and it have expired, he will need to login again too.
If he login, he gets a token for 7 days, if he doesn't use it anymore and after 20 days he comes again, he would need to login again, the server will just decline your petitions until you do so.
What I would do if you use something like angular on the frontend is to check the token validation on startup so you can have a nice user experience.
What I don't understand about your question is de caching thing though.
In addition to #Jesus answer, you can think about implementing a refresh token system: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
In the hotel-example, your hotel-card (access-token) would be invalid after time X, but at the reception you can use your passport (refresh-token) to get a new hotel card again.
You could store the refresh token in the database with additional data about the device the user is using, allowing him to disable the device in case it gets stolen.
Example:
first correct client login: Create a refresh token which is valid forever (until it gets deleted or invalidated)
store refresh token in database
return access token (JWT) with expiration time to client ( this token gets not stored in database)
for the next request, the client sends the access token
Now Check if the access token is expired:
5.1 Access Token not expired, all okay
5.2 Access Token expired, check if there is a refresh token in database
5.2.1 Refresh Token is in database, return new Access Token
5.2.2 No Refresh Token in database, return 401 / logout, User has to login again
Hope this helps.
You need to persist the JWT on the client so that it’s available across page loads, the most secure strategy is an HTTPS-only cookie. This will send the JWT to your server on every request and the server can check the validity of the token and reject it if it's expired. How you handle the expiration is dependent on the type of web app you have.
For a single-page application (e.g. Angular.js apps) you would want to structure the application so that it makes an initial request of the server before it bootstraps the rest of the application. If the server sees that the JWT in this request is expired it would issue a 401 response. You application would respond to this response by rendering a login form. Otherwise it would continue with the assumption that the JWT is valid and can be used to access the required resources. If, at any time, the app sees a 401 it should bring the user back to the login form.
For traditional web apps that render their pages on the server: for any request that has an expired JWT (as read from the cookie) the server should issue a 302 redirect to a login form.
I think what you are asking is how to invalidate a JWT server side for long expiry tokens (e.g. "remember me" functionality)?
I ran into this issue myself recently and ended up using a unique user secret to invalidate the token, when the user attempts to validate a token that was produced with an old secret it will fail. The username can be found in the decoded JWT pre verification.
You could probably even use the users password salt for this, that way any current JWT's would be invalidated when a user changes their password (assuming you also change the salt at the same time), this may be problematic though as the password hash and JWT's would become tightly coupled
I can think of one way, but it is not really defined the standard.
What about adding another kind of expiration date with different lifespan to the claims? With two claims, we can treat the shorter one of it as the resource access expiration date, and the longer one as the refresh expiration date, e.g.
{
"iat": /* current time */,
"bbf": /* current time + 1 hour -- expired means no resource access */
"exp": /* current time + 1 week -- expired means cannot refresh */
}
(Note: I use bbf for the shorter expiration date. No specific reason, just because it has 3 characters in length.)
So with "remember me" checked, when the user reconnects, he can use the same token to request for a new one, but not to access the resource. With this, all relevant data is contained within the token -- no extra token required.
And lastly, when "remember me" not checked, just use the same lifespan for bbf and exp.
I need to migrate my FB app away from using the offline_access permission. As I understand it, server-side OAuth should return a long-lived (60 days) access_token once the user has authenticated.
Once those 60 days are up, I have to request a new token. But, can I do this transparently without requiring the user to revisit Facebook? I understand that the user won't be prompted for the same permissions, but:
a) the redirect_uri parameter must point to a URL where I can process the OAuth request, which makes it difficult for a transparent operation
b) many of my Graph API calls are initiated from AJAX requests hitting my server. If these are rejected due to an expired token, I can't redirect the user away without breaking my application flow.
So my question is, can this be done in a completely transparent manner? I'm assuming the answer is 'No' but bugging the user every 60 days - especially if they've been using the app regularly for 59 days - seems overkill.
It does indeed look like the answer is "No"... Under Scenario 3
Note: The user must access your application before you're able to get
a valid "authorization Code" to be able to make the server-side OAuth
call again. Apps will not be able to setup a background/cron job that
tries to automatically extend the expiration time, because the
"authorization code" is short-lived and will have expired.
We're facing the same problem and it looks like we're going to be forced to bug the user every 60 days. Thankfully this is a relatively minor part of our system and all the AJAX calls are made to our servers which in turn query fb - so we've got a layer of abstraction there where we can hand back cached data/control messages to manage application flow which gives us some wiggle room in terms of failing gracefully until we can get pending data stored and redirect the user appropriately.
Incidentally, it's worth noting that according to the roadmap offline_access will officially become deprecated on 3rd Oct 2012.
I am trying to get my head around secure authentication. Here is the safest method I can think of.
Send an encrypted username + SHA-256ed password to the server and wait for a yes / no response. But the problem with this is a hacker could hack the response to be a yes when it should be a no, giving them unauthorized access to that account.
I am thinking you could work around it by encrypting the response and then, instead of storing it in a Boolean, calling a function that changes state of the application. But because the hacker can make the server say no and yes from his control he can find out the encryption key and still change the result.
That seems kind of insecure, right? What's stopping the hacker from isolating the function that logs you in or the Boolean?
Or am I just being naive and everything really is that insecure? I suppose the only real safe way to do it is to store if the user passed authentication on the authorization server and do a quick Boolean check to see if the user is logged in before every server action.
As Banthar said in his comment, the authorization check should always be performed on the server.
The standard way of implementing this kind of thing is by using a token: the client sends a username and password to the server. If the credentials given by the client succeed authentication, then the server generates a security token, stores it somewhere for later chacks and also sends the token back to the client. For every following request to the server, the client should send the token along with the request parameters, allowing the server to check if the token is valid. The server executes the request only if it can verify that the token is legitimate and authorized, any doubt should result in the server revoking the token.
This method is quite similar to the one you describe in the last part of your post.
The token generated by the server should be a value which cannot be forged: it cannot be a simple integer value incremented for each generated token, since a hacker could easily predict a valid value. It cannot be built using only information available to the client, for the same reason (although it would require more work for a hacker, he could ultimately forge a valid token). Also, on the server, the token should be attached with information allowing the server to easily and uniquely verify the token: a small variation in the connection information should result in the token being revoked. Token values should never be reused (with a token of finite length, there will still be a chance that a token value is reused, so figure out a length which is a good compromise between security and practicability). Finally, the token for a valid session should be regularly updated during the session, to prevent a malicious user steeling the session.
There are many ways to implement this, but the details depend on the security level you are trying to achieve. Using some sort of secret key to generate the token on the server is generally a bad idea, since there is always a chance that the key is leaked. The time when the token is generated may also be predictable. Pseudo-random number generators available to any programming languages have to be properly seeded so that the sequence of numbers cannot be predicted.
Finally, note that no authentication logic ever is completely safe: building more safety in your logic only makes the job harder to a hacker. Think about the incentive for a hacker to break into your system, and devise your logic so that the amount of work for breaking into the system is not worth the resource cost (time, money, specialty hardware...). And do never forget that obscurity does not mean security: let people review your process and comment on it, they may well think about some flaw that you had not seen.