JSON Web Tokens
jwt.io
jwt.io
I've recently incorporated JWTs into my own application. One of the questions I'd like to ask other HNers is how you deal with token expiration. I don't want to reissue a token if I don't have to, but I don't want to create permanent tokens either. An obvious solution is to embed an expiry in the token and check against that, however I don't think that'll lead to a very good UX if tokens "randomly" expire. I've come up with two solutions: 1.) Each user has a session seed token that is used as the secret and thus a user can log out of all sessions by requesting a secret change. This works because any previous JWTs are now invalid because they cannot be validated with the new secret. 2.) I could ping the server periodically (or decode the JWT on the client side) and check when the token expires. Shortly before the token expires, I could request a new one. This doesn't solve the problem of tokens expiring when the user is offline though. Anyone have any better solutions?
This way you can store (in an app, or a browser) the less sensitive refresh token (which might expire after a week or so) instead of the highly sensitive permanent auth credentials.
Here are my two cents:
- Web Apps: If you set an expiration of 1 week, do not use the token for 1 week. Use it for a day and then use the token to get a new token. This way every time your user uses the application, he gets one extra week logged in. This is not different than the normal concept of session and cookies.
If the user does not use your application for a week, next time he go to your app, he will have to login again and this is fine and widely accepted.
- For Mobile/Native Apps: you can use the same explained above, but that's not how most of the mobile applications work these days, I can open facebook after a month without using it and I'm sure I will not need to login again. One way you can do this is to use a refresh token that never expires to fetch a JWT that does expires. The problem with a token that never expires is that it never expires, what happen if your phone is stolen?. In my opinion, there must be a clear and easy interface where the user can revoke these tokens but looking at random alphanumeric characters wont help, so the best practice will be to show something like "Revoke access on John's IPad" this means that the refresh token must be requested for an specific device name.
Certain events can trigger things, if you lost your wallet (at least in Argentina), first thing you do is to call the bank to disable your credit cards. If you forget your laptop in a friend's house and you don't want then to read your Facebook you will probably change your password. Changing the password is usually a good event to
1. Revoke all refresh tokens (for native apps)
2. Anchor the "iss" date for JWTs, this means that tokens issued before the last password change are not longer valid.
Because changing the password can have other purposes, you can also put a prominent button in your UI: "Close session on all browsers and devices", this will delete all refresh token and store the timestamp to check against the JWTs.
We might write a blog post soon about this on Auth0's blog: https://auth0.com/blog.
* Set expiration to a low value (~15 minutes)
* Every generated JWT also gets added to an "issuedTokens" collection for each user
During JWT validation, if the expiration has passed, an "Expired" response would be returned from the server (ex. 401 w/ "Expired" in body). When the client receives this status, it should initiate a refresh process which trades an expired token for a new one.
The refresh endpoint on the server should take an expired token and perform the following:
1. Validate token (except expiration)
2. Retrieve user ID and check if token is in its issuedTokens collection
3. Issue a new JWT
4. Remove the expired token from the collection and add the new one
Upon failure of any of these steps, an Unauthorized error should be sent to client which then requires logging in again.
To prevent a never-ending build-up of issued tokens, we can set a TTL on the tokens in the issuedTokens collection. Set the TTL value to the amount of time that a login should be active for before requiring logging in again.
This approach doesn't hit the database unless you keep trying to refresh an expired token. In which case you can make use of a cached blacklist of failed tokens. This can reside next to the application itself if treated as a cache layer.
This is definitely just a work-in-progress solution that I'm about to test out. Let me know your thoughts on it.
Looks definitely easier than SAML.
With the exception that it's only signed, not encrypted, yes. SAML does have the advantage in that regard, but I've never been a fan of using clients to transport sensitive information anyway, even encrypted.
We (Auth0) are heavy promoters of the usage of JWT. Here are some articles about using JWT instead of cookies on single page apps with APIs, and its pros/cons.
https://auth0.com/blog/2014/01/07/angularjs-authentication-w...
https://auth0.com/blog/2014/01/27/ten-things-you-should-know...
What is the best and recommended way to implement a "remember me" feature?
I'm using the "angular-fullstack" yeoman generator (https://github.com/DaftMonk/generator-angular-fullstack) which uses your npm packages, but it lacks of a feature like that, and the app is pretty much unusable, user must log in every time after closing the browser...
Client side access is pretty well understood. A JWT can be stored in a cookie and then added to Ajax requests as a bearer token, for example.
The server-side code will typically have some way of validating the client, such as an encoded cookie. This will be used to build a user object of some sort, which can be used to run authorization checks. When the server side needs to access the API, the user object can be serialized into a JWT and added as a request header, similar to typical client-side access. If it's done well, the API can use a very similar user object to check authorization. Another option is just to do JWT pass-through. If this is done, the signature should at least be checked to avoid facilitating an impersonation attack.
JWTs have built in signing to ensure that the user object is intact. All that is left is to encrypt the channel with SSL.
I think what everyone needs to remember is that SSL is a must for these things. If you're issuing non-expiring tokens over non-SSL you're just giving the keys to the castle away. Another thing that should be considered is token storage. I'm using local storage right now which works for me, but it just means I need to be more careful than ever about XSS exploits, because there's no "HTTP only" option for local storage!
A side note for anyone considering the use of timestamps within the payload for expiry: note that if you are going to have multiple machines verifying expiries, they will need to be using NTP to ensure that all machines have the same current timestamp at all times.
There is also JSON Web Encryption, built on top of JWT, which provides encryption in addition to signatures. https://tools.ietf.org/html/draft-ietf-jose-json-web-encrypt...
The main downside is that the representation (base64-encoded json) is pretty bulky for something that might be used in HTTP headers and URLs, but it does make them easy to debug.
[0] All but six of Z85's special characters get encoded by Javascript's encodeURIComponent:
: + = ^ / ? & < > [ ] { } @ % $ #
[1] URI-safe versions of Base64 (as used by JWT) use 4 characters for every 3 bytes. Z85 uses 5 characters for every four bytes, but 17 of those 85 characters require three URI characters to represent, meaning that a Z85-encoded byte requires 1.75 URI characters per byte on average: (68 * 1 + 17 * 3) / 85 = 1.4 uri_chars/char
1.4 * 5 / 4 = 1.75 uri_chars/byteHTTP does not define any limit for headers, but most of the Web Servers have a default limit, Apache 8kb, IIS 16kb, nginx 4kb (see this question on SO [1]). If your JWT exceeds these limits you will get a "413 Entity Too Large".
It gets only worse if you need to use a query string instead of a header because the limits are lower and IE has a limit too [2].
Solution: carefully design your JWT, what information you will put on there. You usually don't need everything, store only the things you will use on every request, like the user id, name, email, roles are good candidates. Do not try to put the entire Facebook or Linkedin profile on a JWT.
Beside the limits, it will make the request bigger to transport and maybe even slower to verify.
[1]: http://stackoverflow.com/questions/686217/maximum-on-http-he... [2]: http://stackoverflow.com/questions/417142/what-is-the-maximu...
https://github.com/jsonwebtoken/jsonwebtoken.github.io/issue...
- What is the most secure algorithm to use when creating the signature?
- Should you do anything else on the server side besides verifying the signature? IE: tracking tokens, rotating keys, etc.
Without knowing much about encryption it seems risky to simply trust a JWT based on signature alone. How hard would it be to actually spoof a JWT with the most secure encryption algorithm?
https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-...
My short answer to “How secure are JSON Web Tokens?”, though, would be that the relevant security issues are likely to come in “around” the use of JWTs, not as a result of JWTs themselves being “weak”. JWT is just a set of conventions for encoding authn/authz claims in JSON and then encrypting/signing the result.
Answering your questions completely depends upon your application. There is, in general, no "most secure" algorithm for encryption and what you handle on the server completely depends upon the security goals of your application.
For example, I'm currently working on something that passes JWTs unencrypted and unsigned because the application simply doesn't need it. Furthermore, the application does have a method of tracing used tokens, but there isn't really a need for rotating keys or anything else like that.
Hope that helps.
I get the fact that security totally depends on implementation. I just need to better understand encryption and the differences between the various algorithms. If anyone knows of any good resources for learning about cryptography and encryption algorithms that would help a lot.
1. They're made up of three .-delimited segments: header.data.sig
2. JWT doesn't prescribe any particular sig algorithm. The header indicates by what method the {data} JSON object was signed to get {sig}. A common sig method is hmac-sha
3. JWT only provides a signature to assure that the {data} was not tampered with. The data is not private at all and easily inspected (which is nice for debugging). JWE can provide encryption http://tools.ietf.org/html/draft-ietf-jose-json-web-encrypti...
And for some: "Why is this useful?". It's useful if my API needs to receive requests to do serious business like delete things or post as your account. How do I know if the request is from a trusted source? Well if the trusted source has a secret key they can use to generate the {sig} according to the {data}, then I can verify that the requester had access to the secret key and therefore trusted.
However, the data in the main request is not encrypted, unless you're doing so via another means.
[0] https://tools.ietf.org/html/draft-ietf-jose-json-web-signatu...
[1] http://tools.ietf.org/html/draft-ietf-jose-json-web-encrypti...
Of course, you could use a holder of token scheme to authenticate in the case of server to server communication. However, in this case you're making an assumption that both servers can prevent access to the shared secret.
In addition to what you described, the JWT spec also supports an RS family of algorithms (asymmetric). It means that you can sign with a private key and verify with a public key.
For instance Google, sign every JWT with the same private secret and publish their key for verification [1]. If you use this, your server-side application not only needs to verify that the JWT signature is correct but also that the audience is your application.
I wrote an example middleware for connect to verify Google's JWTs [2].
[1]: https://developers.google.com/accounts/docs/OAuth2Login#vali...
Or is this for use in URL-passed data (like email links?) If so, is this better than including a token as a key to a one-time, limited-time activity stored on the server?
The simplest way of describing it is that with HTTPS, when sending data to/from a server and a client (the client may even be another web server) you can be assured no one but the server or client can see or tamper with the data in transit.
But the client is still able to trick the server, or vice versa, at the application level. To prevent that you need a message signing scheme (aka a MAC), and this is an example of one.
For the case of password reset links from an email, generally speaking there's no point in using something like this; a one-time random token that you track and expire on the backend makes more sense. You'd only want to use a MAC if you need to freeze some kind of state in the URL and retain it, like perhaps a user's IP address. Then you can verify that the user's real IP address does indeed match the IP address in the URL; they can't tamper with the URL to change the IP address if a MAC is used.
I don't know why anyone would want such a feature for a password reset function, and you could also replicate that same behavior just by storing the IP on the backend as well (though while also perhaps making your application somewhat more complex in the process), but that would be one example of doing something like that in a secure manner while still letting the client keep track of the state instead of the server.
One common use of tokens like this is to defer state retention to all your clients so your server can do less work per request and store less data. Simply verifying that the MAC for a message is valid in every request is a lot faster than making a database/data store query to return session info for every request.
Generally for web app development, I think MACs tend to suffice for the vast majority of use cases.
For server-to-server authentication, there is less to recommend this, although it does allow services to authenticate without having to check a credential against a data store someplace.
I guess you could could kludge it into a form with a method="SRP" and have the browser do it's thing with the username and password field.
https://github.com/hapijs/hapi-auth-hawk
https://github.com/hueniverse/hawk
Supported langs: https://github.com/hueniverse/hawk/issues?q=is%3Aclosed+labe...
It's also really limited in that there is no API to get order status to check if a subscription is still active - so if you miss the cancellation postback, you have no way of knowing which subscriptions are active and which aren't. You also can't change the value of an active subscription. That was the biggest thing people were asking about when they introduced it at IO three years ago, and it's still not fixed.
So if you are in a country where you have a better option you might want to consider it :)
We (Firebase) use JWTs to integrate with an existing app's userbase[1].
[1] https://www.firebase.com/docs/web/guide/simple-login/custom....
I've been really pleased with how simple and straightforward it is for implementors. It's good to see it getting more visibility. Thanks to Auth0 for educating the community.
https://github.com/sahat/satellizer
It's still a very new project, but looks promising.
The only qualm I would have is that there's only a Ruby server side example, with Node as the test suite. I would say expanding that to include more example languages would be beneficial.
I've been using the Google library[1], in a dropwizard app and it's pretty old and not great.
OTOH, I do recommend both Dropwizard (the OAuth stuff lets JWT drop straight in) and Satellizer[2] for Angular.JS JWT stuff.
I've implemented something very similar to JWT (based on the old AWS auth scheme), but each client is given an API Key and their own Shared Secret. How does the server know whose shared secret it should use to validate messages?
The client doesn't get a shared secret. JWT is a server sending a token to the client which the client then sends back like a cookie. The client isn't allowed to modify the token or the data inside it.
It's like a signed cookie.
(EDIT: typo)
The OAuth protocol doesn't specify which token format to use. Normally people have been using an "opaque" token, this is a token that doesn't have any meaning nor content but the meaning is stored somewhere. Here is an example of a table storing tokens and the scopes (permissions) associated to them. Every time an API Call is made, you would have to check against this table to see if the token sent in the Authorization header has the necessary scopes to call the API.
token | scopes oiajoeihfe9jh9283n | read.userinfo, post.friends uhuernvmiwmwo38h2g | read.userinfo
If you would use JWT you wouldn't have to store that information because it would be part of the token (i.e. stateless)
This would be a counterpart JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjM0NTY3O DkwLCJhdWQiOiJodHRwOi8vbXlhcGkiLCJzY29wZXMiOlsicmVhZC51c2VyaW5 mbyIsInBvc3QuZnJpZW5kcyJdfQ.tnLKyCWhVfkj2v15maCBJBVgPO08zFp2Lh n4Vkb4OoU
header: { "alg": "HS256", "typ": "JWT" }
payload: { "user_id": 1234567890, "aud": "http://myapi", "scopes": ["read.userinfo", "post.friends"] }
Google now changed their Authentication protocol to use OpenID Connect [1], which is a layer on top of OAuth plus a JSON Web Token. The thing about OpenID Connect which makes it useful for Authentication is that you can verify that the token (JWT) has been issued for your application (and not be used by another application) which was something the OAuth was lacking and a common vulnerability [2].
[1] https://developers.google.com/accounts/docs/OAuth2Login [2] http://homakov.blogspot.com.ar/2012/08/oauth2-one-accesstoke...
I find jwt a tinge too complex. On the other hand no solution for unified AAA exists on web that makes sense: HTTP is a stateless protocol.
I sometimes wish people wake up from the Oauth insanity and realize using a statefull TCP connection would drop the sessions problem.
Why use stateful protocol (Oauth) for a stateless protocol (HTTP) over a statefull protocol (TCP)?
Emitting token lasting more than 1 hour impersonating the user in an hostile environment seems quite a lot of risk (mathematically speaking)
I must be a grumpy old dev, but I kind of hear the oauth sweet song of easy secure cross security token like sirens trying to seduce me for crashing my ship on the havoc of security.
Security is a mine field. One step out of the «right way» and boom, it does not work while burning 25% of your CPU power, an hidden tax.
Oauth protocol is a multi-dimensionnal maze designed under LSD at my opinion, and I kind of feel it unsafe to take.