New to token authentication, OAuth, or JSON Web Tokens? This is a great place to start!
First, what is a JSON Web Token, or JWT (pronounced “jot”)? In a nutshell, a JWT is a secure and trustworthy standard for token authentication. JWTs allow you to digitally sign information (referred to as claims) with a signature and can be verified at a later time with a secret signing key.
The process by which an application confirms user identity is called authentication. Traditionally, applications have persisted identity through session cookies which rely on session IDs stored server-side. In this structure, developers are forced to create session storage that is either unique and server-specific, or implemented as a completely separate session storage layer.
Token authentication is a more modern approach, designed solve problems server-side session IDs can’t. Using tokens in place of session IDs can lower your server load, streamline permission management, and provide better tools for supporting a distributed or cloud-based infrastructure. In this method, tokens are generated for your users after they present verifiable credentials. The initial authentication could be by username/password credentials, API keys or even tokens from another service. (Stormpath’s API Key Authentication Feature is an example of this.)
If you encounter a JWT in the wild, you’ll notice that it’s separated into three sections, the header, payload, and signature. (Follow along with Stormpath’s open-source Java JWT tool as we dissect the anatomy of a JWT!) Here’s an example of a typical JWT:
In this example, Section 1 is a header which describes the token. Section 2 is the payload, which contains the JWT’s claims, and Section 3 is the signature hash that can be used to verify the integrity of the token (if you have the secret key that was used to sign it).
When we decode the payload we get this nice, tidy JSON object containing the claims of the JWS:
"name": "Robert Token Man",
"scope": "self groups/admins",
The claims tell you, at minimum:
- Who this person is and the URI to their user resource (the sub claim)
- What this person can access with this token (the scope claim)
- When the token expires. Your API should be using this when it verifies the token.
Because the token is signed with a secret key you can verify its signature and implicitly trust what is being claimed.
Per the JWT Spec, “JWTs represent a set of claims as a JSON object that is encoded in a JWS and/or JWE structure.” The term “JWT” technically only describes an unsigned token; what we refer to as a JWT is most often a JWS or JWS + JWE.
In the JWS scheme, the server signs the JWT and transmits it to the client with the signature. The signature provides a guarantee that the JWT claims have not been forged or tampered with. However, the JWT is not encrypted (the contents are essentially plaintext).
The JWE scheme, on the other hand, encrypts the contents without signing it. This brings confidentiality to your JWT, but not the security of signing and enclosing the JWE inside a JWS.
OAuth 2.0 is a framework for interaction with a service that can delegate authentication or provide authorization. It is widely adopted across many mobile and web applications. OAuth 2.0 does not specify a token format, but JWT is rapidly becoming a defacto standard in the industry.
Within the OAuth paradigm, there are two token types: Access and Refresh Tokens. When you first authenticate, your application (and thus your user), is typically given both tokens, but the Access Token is set to expire after a short period (this duration is configurable in the application). Once the initial Access Token has expired, the Refresh Token will allow your application to obtain a new Access Token. Refresh Tokens have a set expiration, allowing for unlimited use up until that expiration point is reached. Both Access and Refresh Tokens have built-in security (when signed) to prevent tampering and are only valid for a specific duration.
Stormpath uses OAuth because it is an industry standard that can be leveraged by any compliant library. Stormpath currently supports three of OAuth’s grant types:
- Password Grant Type: Provides the ability to get an Access Token based on a username and password
- Refresh Grant Type: Provides the ability to generate another Access Token based on a special Refresh Token
- Client Credentials Grant Type: Provides the ability to exchange an API Key Pair for an Access Token. This is supported through the API Key Management feature
So, you’re sold on tokens, now, how do you use them in your application?
Well, if you’re a Java developer you should start with JJWT. JJWT is a Java library providing end-to-end JSON Web Token creation and verification, developed by our very own Les Hazlewood and maintained by a community of developers. Forever free and open-source (Apache License, Version 2.0), it was designed with a builder-focused interface hiding most of its complexity.
Because of JJWT’s fluent interface, the creation of the JWT is basically a three-step process:
- The definition of the internal claims of the token, like Issuer, Subject, Expiration, and ID.
- The cryptographic signing the JWT (making is a JWS)
- The compaction of the JWT to a URL-safe string, according to the JWT Compact Serialization rules
The final JWT will be a three-part Base64 encoded string signed with the specified signature algorithm using the provided key. After this point, the token is ready to be shared with the other party.
Here’s an example of creating the JWT from above using the JJWT library:
String jwt = Jwts.builder()
.claim("name", "Robert Token Man")
.claim("scope", "self groups/admins")
Once you have a JWT, you typically deliver it back to the client that requested it. The client then stores it and passes the Token in requests to your application. This is usually done with either a cookie value or an authorization header in HTTP. For example:
Authorization: Bearer eyJraWQiOiIzMUUzRDZaM0xaMVdFSEJGWVRQRksxRzY4IiwiYWxnIjoiSFMyNTYifQ.eyJqdGkiOiI2a3NjVFMyUjZuYlU3c1RhZ0h0aWFXIiwiaWF0IjoxNDQ1ODU0Njk0LCJpc3MiOiJodHRwczovL2FwaS5zdG9ybXBhdGguY29tL3YxL2FwcGxpY2F0aW9ucy8zUUlNbEpLS04yd2hHQ1l6WFh3MXQ4Iiwic3ViIjoiaHR0cHM6Ly9hcGkuc3Rvcm1wYXRoLmNvbS92MS9hY2NvdW50cy8xeG15U0dLMXB5VVc1c25qOENvcmU1IiwiZXhwIjoxNDQ1ODU4Mjk0LCJydGkiOiI2a3NjVE9pTUNESVZWM05qVTIyUnlTIn0.VJyMOicMOdcOCtytsx4hoPHy3Hl3AfGNfi2ydy8AmG4
Validating the JWT allows you to verify its authenticity (by checking its digital signature you can check that it is not expired and verify that it hasn’t been tampered with) and get information about the user sending the token.
Here’s an example of validating the JWT that we created above:
String jwt = <jwt passed in from above>
Jws<Claims> claims = Jwts.parser()
String scope = claims.getBody().get("scope")
assertEquals(scope, "self groups/admins");
If the signature is incorrect, the call to
parseClaimsJws will throw a
SignatureException. Once successfully parsed, individual claims can be obtained and checked as in:
String scope = claims.getBody().get("scope").
JJWT carries out a variety of validations while working with the JWT. All JJWT-related exceptions are
JwtException as the base class.
These errors cause specific exceptions to be thrown:
: thrown after a validation of a JWT claim failed
: indicating that a JWT was accepted after it expired and must be rejected
: thrown when a JWT was not correctly constructed and should be rejected
: indicates that a JWT was accepted before it is allowed to be accessed and must be rejected
: indicates that either calculating a signature or verifying an existing signature of a JWT failed
: thrown when receiving a JWT in a particular format/configuration that does not match the format expected by the application. For example, this exception would be thrown if parsing an unsigned plaintext JWT when the application requires a cryptographically signed Claims JWS instead
There are a number of other Exception classes that JJWT uses. They all can be found in the
io.jsonwebtoken package in the JJWT source.
The real question here is, are you using them securely? At Stormpath, we follow these best practices, and encourage our clients to do the same:
- Store your JWTs in secure, HttpOnly cookies. This prevents Cross-Site Scripting (XSS) attacks.
- If you’re using cookies to transmit your JWTs, CSRF protection is super duper important! Your cookies can be used maliciously by other domains that make requests to your website without your user’s consent. If your server blindly authenticates a user, simply because they have a cookie, then you’ve got more problems than your hard drive size. You’re also allowing CSRF attacks, where other websites trigger state-changing actions on your server without your users’ consent. This is possible because the browser will always send the user’s cookies automatically, regardless of how the request was triggered. Use one of the many CSRF Prevention measures to reduce this risk.
- Sign your tokens with a strong key that is available ONLY to the authentication service. Every time you use a token to authenticate a user, your server MUST verify that the token was signed with your secret key.
- Do not store any sensitive data in a JWT. These tokens are usually signed to protect against manipulation (not encrypted) so the data in the claims can be easily decoded and read. Encrypt your tokens if you have to put sensitive, non-opaque information in them. The secret signing key should only be accessible by the issuer and the consumer; it should not be accessible outside of these two parties.
- If you are worried about replay attacks, include a nonce (jti claim), expiration time (exp claim), and creation time (iat claim) in the claims. These are well defined in the JWT Spec.
Stormpath supports the development of several JWT-related, open-source developer tools, including:
JJWT is an easy to use tool for developers to create and verify JWTs in Java. ike many libraries Stormpath supports, JJWT is completely free and open source (Apache License, Version 2.0), so everyone can see what it does and how it does it. Do not hesitate to report any issues, suggest improvements, and even submit some code!
JSONwebtoken.io is a developer tool we created to make it easy to decode JWTs. Simple paste an existing JWT into the appropriate field to decode its header, payload, and signature. JSONWebToken.io is powered by nJWT, the cleanest free and open source (Apache License, Version 2.0) JWT library for Node.js developers.
The new kid on the block, JWT Inspector is an open source Chrome extension that allows developers to inspect and debug JWTs directly in-browser. The JWT Inspector will discover JWTs on your site (in cookies, local/session storage, and headers) and make them easily accessible through your navigation bar and DevTools panel.
Looking to learn more about JWTs, token authentication, or user identity management? Here are some further resources from our team:
- Token Authentication for Single Page Apps
- OAuth Token Management with Spring Boot and Stormpath
- Token Authentication for Java Applications
- Build Secure User Interfaces with JSON Web Tokens
- OAuth is Not Single Sign-On