Invalidating JWTs on Permissions - json

Do people typically store permissions in a JWT? I've seen example that might have admin: true or scopes: ['add_foo', 'delete_foo', 'read_foo']. And this seems fine, other that the potentially large size that the JWT could become if there are a lot of permissions/scopes. It seems like it would be really useful as you wouldn't need to hit a DB or cache to get the users permissions as long as the JWT can be verified.
My main question though is how these would be invalidated in the event of a permissions change.
For example, sys admin Joe, revokes the 'add_foo' and 'delete_foo' permissions from user Bob, but keeps the 'read_foo' permission. In this scenario user Bob should not have his token entirely invalidated and need to log back in, he should basically be forced to get a new JWT with the new permissions and carry on as normal.
I've seen examples explaining issuing a new JWT in the event of a password change, but the difference here is that sys admin Joe does the update to user Bob. Thus, there is no opportunity in this workflow for user Bob to get the new token immediately.
Most examples suggest for invalidation maintaining a black list of revoked tokens, or changing a DB record ID so the token is no longer valid, or having a per-user secret and changing that.
I see that all of these would work for the revoking of the token and test that its invalid, but how does the user then get a new token? their current JWT is now invalid? Trying to do anything with it should fail.
I've seen mention of a "refresh token". Are these widely use? Are they secure on the web or mainly used for mobile apps where the refresh token is harder to obtain. It seems like it would be reasonably easy to steal a refresh token via browser dev tools or similar and then someone would have access forever to that account until the unauthorized access was noticed and the refresh token revoked.
Maybe in this scenario forcing user Bob to re-authenticate is not such a big deal? Permissions probably don't change too often.
Thanks, Mike.

You can set expiration date (for Web app we are usually using 15 min - 30 min, for mobile 1 week). When you set Issued at claims parameter ("iat"). Then every time when you validate token you should check the token's "age". If it older than 5 min you load data from DB and create new token with current "iat" value.

When permissions change you should invalidate the issued tokens for this user. There are different techniques to use. See Invalidating client side JWT session
But consider that revoking tokens is not a recommended practice because you lose one of the main advantages of JWT: It does not require server storage.
The objective of Refresh tokens, as defined in Oauth2.0, is allow applications to obtain a new access token without re-authenticate
Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain a new access token when the current access token becomes invalid or expires,
If the permissions do not change frequently it may be easier to re-authenticate user, and if they change much consider whether they really should be included in the token

Related

OAuth2 Session Timeout vs Session ID Timeout and Refresh Tokens

In my app, I allow my users to authenticate with their existing google, microsoft, etc accounts via OAuth2.
Everything runs smoothly. Upon getting callback to local redirect url, I successfully request and receive bearer token from endpoint. With access token in hand, I then request UserInfo from user info endpoint. I then compare email address in UserInfo JSON object with the email address registered in user record and if they match, I consider user signed in.
Now, my question is regarding bearer token and session timeouts.
Google bearer token looks like it authorizes for 60 minutes; while my server session lasts 30 minutes (I haven't changed the default).
Since user already got successfully authenticated, the session id will remain active and alive while there's activity within every 30 minutes. However the bearer token expiration will have expired after an hour.
I would normally assume that I need to refresh the access token before it expires so long as there's activity within the established server session. However, google does not appear to have a refresh token endpoint.
But even if it did, would it be desirable to do this?
Or since the fact that I have an active session id from an authenticated user is enough to allow access to protected resources while only the session id is 'alive'?
I'm assuming it is, since some websites allow customers to maintain their sessions for days at a time, at which time, bearer token would have expired long before.
And lastly, how long would you recommend I keep my users (customers, really) with an open session? My website is on online store.
Thanks to all!
Your session can be completely detached from Google's session. You should only be concerned whether your session is still active. The validity of the access token from Google is not relevant here. Remember that the expiration time of an access token has, in fact, nothing to do with a user's session at all. E.g. you log in a user using Google. The user authenticates at Google and you get an access token, which is valid for 60 minutes. The user then logs out at Google. Your access token will still be valid until that 60 minutes pass, even though the user logged out from Google, and her session is no longer valid there.
As for the length of the session, this is really up to you. If you know your customers are likely to come back often, and you want to make it easier for them you can even keep a session indefinitely. In such a scenario you should think about security and privacy - if the user leaves their account logged in on a shared computer, how much could it hurt them if someone else manages to use their session after a week or so. If you know your customers are likely to come back every few weeks or months to your store, then it really doesn't matter if you keep the session open for a day or five. Most of them will have to log in again anyway.
So to answer the question of the length of the session you should study the behavior of your users and take into account security and privacy issues.

Login Security using jsonwebtoken

I am currently working on a website using React where I want to be able to have user login. Right now my strategy is to send form data to the server (express) on submit, and if the info matches a user in my DB, the server sends back a signed JWT with no sensitive information (just the username).
Once the client receives the JWT, I am adding it to localStorage as well as adding the decoded data of it to my redux store. I plan to have my redux store holding the currently logged in user.
I believe there may be a security issue in my site because currently I have it so when the user first arrives at the site, If there is a JWT, it is added to my axios headers and the decoded JWT is set to be the current user. The code looks like this:
if(localStorage.jwtToken) { // If token present, most likely a user is signed in
setAuthorizationToken(localStorage.jwtToken) // Set that token to head all api calls
store.dispatch(setCurrentUser(jwt.decode(localStorage.jwtToken))) // Set user in redux store
}
Currently I've found that if someone just goes into my localStorage, copies my JWT and adds it to their localStorage then bam, they are me. I'm unsure if this is really a security flaw because the only way I've recreated this myself is by physically copying the token from one browser to another. But in general this seems very unsafe that just taking my token steals my identity.
If anyone knows a way to make this more secure or if there is a better strategy, or at least tell me what I'm doing wrong that would be highly appreciated.
How can another person get your token? Give expire time to token needed. Maybe try different way for securing token, especially give more security in API side. When logging in, store log activity in database and create unique field to identificate it such ip address or user-agent, or maybe detect is that user have been hit login endpoint before or not.

Service now api how to comment as specific user

I'm working on a project that consumes Service Now API (Rest). To do so our client has registered us as a user in order to login and make all service calls we need to. This project has an interface where users can login once they have an account on Service Now as well, the username they type to log in has nothing to do with service now by the way, but later they associate theirs service now users to it. They can do some operations through this interface, where all of them are done using the integration user/pass not their service now users theirselves, even because they do not need to share their passwords with us. But it's needed to track the correct user to register on service now and I'm in trouble specifically about commenting on an incident. The endpoint to comment is the following :
http://hostname/api/now/table/incident/{sys_id}
where request body is a json object just as simple as :
{
"comments": "My comment is foo bar"
}
but when this comment is registered on Service Now it is under integration user instead the user which commented. Is there any way I could keep a specific user, considering I already have the user id on Service Now ready to inform it on the request the way it should be.
I tried reading Service Now documentation but had no clue how to solve it, altought I've found something about impersonate
This is happening because you're being proxied through the "Integration User" instead of your own account. As long as this is the case, your comments are going to be attributed to the Integration User.
I can think of two ways to fix this issue.
Ask the client to log you into their system directly as a user.
Implement a special API (Scripted REST API, available in Geneva or later) that allows you to identify the Incident and enter the comment, and then the script forges the comment on your behalf, attributing authorship correctly.
The first solution can be expensive due to possible additional licensing costs.
The second solution will require a willing client to devote 2-3 hours of development time, depending on the programmer.
Firstly, you need an integration user with suffient rights. Our integration user has suffient rights out of the box, but your story could be different. A quick check is to try impersonate as other user using menu.
Login as integration user to ServiceNow instance.
Go to https://{instance}.service-now.com/nav_to.do
Click on username at top right corner. This is a drop down.
There should be at least three menu items: "Profile", "Impersonate User", and "Logout". If you do not have "Impersonate User" in this menu, your integration user miss some permissions. Contact system administrator if you miss this menu item to configure appropriate permissions.
Then you need to find sys_id of user that you want to impersonate. For example:
https://{instance}.service-now.com/api/now/table/sys_user?sysparm_query=user_name={username}&sysparm_fields=sys_id
If you have suffient privileges, you could invoke the folling endpoint with sys id of user that you want to impersonate:
HTTP POST to https://{instance}.service-now.com/api/now/ui/impersonate/{user_sys_id} with body "{}" and content type "application/json". You need to provide HTTP basic authentication to this query as your integration user.
The response code on success is 200. The response body could be ignored. The interesting result of this response is a set of cookies for impersonated user in response headers. These cookies could be used for subsequent REST API calls until they expire. Use some HTTP rest client dependent method to capture them and to provide them to next calls.
For Apache HTTP Client (Java), I'm creating http client context using:
HttpClientContext context = HttpClientContext.create();
context.setCookieStore(new BasicCookieStore());
Pass thing context to impersonation request and to subsequent API calls until I get 401 reply, after that I'm reaquiring cookies. Setting new cookie store is important, as otherwise some default cookies store is used.
Two things to note:
This API looks like internal one, so it could change at any time. If it happens, look for what "Impresonate User" menu item does, and repeat it youselves.
ServiceNow permissions are quite fine-grained, so the target user could lack permissions to perform operation. In some cases, if there is no permission to update the field the operation PATCH on object returns reponse 200, but field is not updated. This introduces a surprising mode of failure when you use impersonation.

Correct HATEOAS response when creating a user account

I have a REST api written in node which uses HATEOAS. The user is required to have an account before they can access the bulk of it.
They register an account with login details, then login to obtain an access token, and then use that token in order to access any endpoints that aren't register or login.
Issuing a get to the root responds with a directory with available actions.
Q: What is the correct response from register, to tell the client what it can do next (i.e. login)?
register technically creates a new resource on the server so a 201 CREATED and a Location header would seem appopriate. However the login reference isn't the location of the newly created resource.
Should I return 201 Created with a Location pointing to the newly created user (e.g. /myaccount or /users/{id} and then include a login link in the response body?
{
_links: {
self: { href: "what goes here?" },
x:login: { href: "/login" }
}
}
Do I not tell the client at all, and require them to do a get on the application root in order to fetch a list of available endpoints. This should include login anyway. Assuming the client had to do that in the first place to get the register link it should already have login.
Expecting the client already to already have the login link feels uncomfortable as it relies on an assumption of the client's prior activity.
Requiring the client to issue another request to the root directory after registering seems mean, inefficient and unnecessary. If the client has just created a resource it seems only fair that the server should respond with what it can do with it next.
I like to have my api's act no differently than a webpage. If you want the UX of your application to be the user is taken to login after they register, then 302 them from a successful register to the login resource. And upon successful login, 302 to them to the appropriate destination (IE, if they tried to access something with no token, then take them to login, with a destination of the original requested resource). That's and important part to your #3. Having a link off the root that leads to login, but you need to protect all the other links such that they indicate (and link to) a login being required to access the resource. The client app should expect to get this login required response at any time as tokens can (and do) expire at any time.
Following on this, it might make sense to do the JWT as a cookie instead of as an Authorization Header, it would make it a bit easier for the client (they just have to setup a cookie jar)..if the client is say a native mobile app that maintains a single connection setup. If it's server to server, then auth header makes sense. I'd go about supporting both to cover both scenarios.
Continuing on the idea of thinking of the api as a web site. Why have them login after registration at all? Why not have the registering of an account end up with the login token being sent? they just set their user/pass, why make them enter it again? I realize with some more exotic architectures the register service can not perform the login action (perhaps it doesn't have the private key to sign the token), but if it is possible i'd consider it.
If you really want to stick to the 201 header (which is fine, just make sure the docs of your register relationship indicate that), then option 2 is the closest in my opinion. A location header to the URL of the account just created a 201 is pretty standard for creating a user. But, i'd not return what you've supposed there. You're kind of returning a account-created resource (the thing with the login link), but do you really need this custom resource? If you want to give some messaging back to the client (like "Account Created") in that resource then absolutely yes, but you could also just give them back the root resource.
tl;dr; Decide what you want your UX to be and then make your API implement your UX.

Get non expiring Access Token from Box or Get access token from box by passing UserName and Password.?

I got the Access Token using Box Api but it is expiring in 1 hour.
What I want here is,
Either I need non expiring access token or get the access token by passing my Box User Id and Password to API.
If above things are possible let me know the way.
Thanks in advance..
You've got what is called a Bearer Token and a Refresh Token. The Bearer token is good for an hour, and the Refresh token is good for 60 days. The Refresh token can be traded in for another pair of tokens, which resets both clocks at the time you do the refresh.
Box doesn't have tokens that you can get via a username-password grant in OAuth2, because that inherently doesn't work for enterprise customers that need to do SSO through their ActiveDirectory / Okta / Ping / 2-factor / SecureID signin flows.
What you probably want is an SDK that handles the refreshing of the token for you. Most users won't ever have to logon a second time, unless they go on vacation for a few weeks. Box has already released several SDKs, all on github with open-source licenses. Most of them take care of refreshing the token for you automatically.
We've also added some enhancements recently (early 2014) to help multi-server implementations work more smoothly with the refresh-token flow, including allowing you to use the old refresh token to get the new token multiple times in a narrow time-window. That helps with both multi-threaded environments trying to get new tokens across a number of threads (or servers). It also helps with the case where you have a network interruption and you don't actually get the new token-pair back from your initial refresh call.