JWT (JSON Web Token) library for Java

JavaJsonWebTokenJwt

Java Problem Overview


I am working on a web application developed using Java and AngularJS and chose to implement token authentication and authorization. For the exercise purpose, I've come to the point where I send the credentials to the server, generate a random token store it and send it back to the client. At every request to the server I'm attaching the token in the header and it works perfectly. For the authentication point of view is perfect and wouldn't need more.

However, I now want to keep track of the user type (admin, regular user...), as well as it's id, or any other unique field; as I understood I have to encrypt that in the token that I'm sending back to the client during the log in action. Is that correct?

Is there any JWT library that you used and can generate, encrypt and decrypt such tokens? A link to the library's API and Maven dependency would be much appreciated.

Thanks

Java Solutions


Solution 1 - Java

JJWT aims to be the easiest to use and understand JWT library for the JVM and Android:

https://github.com/jwtk/jjwt

Solution 2 - Java

Solution 3 - Java

By referring to https://jwt.io/ you can find jwt implementations in many languages including java. Also the site provide some comparison between these implementation (the algorithms they support and ....).

For java these are mentioned libraries:

Solution 4 - Java

This library seems to work well: https://code.google.com/p/jsontoken/ .

It depends on Google Guava. Here are the Maven artifacts:

<dependency>
	<groupId>com.googlecode.jsontoken</groupId>
	<artifactId>jsontoken</artifactId>
	<version>1.0</version>
</dependency>
<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>18.0</version>
</dependency>

The library is in fact used by Google Wallet.

Here is how to create a jwt, and to verify it and deserialize it:

import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.util.Calendar;
import java.util.List;

import net.oauth.jsontoken.JsonToken;
import net.oauth.jsontoken.JsonTokenParser;
import net.oauth.jsontoken.crypto.HmacSHA256Signer;
import net.oauth.jsontoken.crypto.HmacSHA256Verifier;
import net.oauth.jsontoken.crypto.SignatureAlgorithm;
import net.oauth.jsontoken.crypto.Verifier;
import net.oauth.jsontoken.discovery.VerifierProvider;
import net.oauth.jsontoken.discovery.VerifierProviders;

import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;

import com.google.common.collect.Lists;
import com.google.gson.JsonObject;


/**
 * Provides static methods for creating and verifying access tokens and such. 
 * @author davidm
 *
 */
public class AuthHelper {

	private static final String AUDIENCE = "NotReallyImportant";

	private static final String ISSUER = "YourCompanyOrAppNameHere";

	private static final String SIGNING_KEY = "LongAndHardToGuessValueWithSpecialCharacters@^($%*$%";

	/**
	 * Creates a json web token which is a digitally signed token that contains a payload (e.g. userId to identify 
	 * the user). The signing key is secret. That ensures that the token is authentic and has not been modified.
	 * Using a jwt eliminates the need to store authentication session information in a database.
	 * @param userId
	 * @param durationDays
	 * @return
	 */
	public static String createJsonWebToken(String userId, Long durationDays)    {
		//Current time and signing algorithm
		Calendar cal = Calendar.getInstance();
		HmacSHA256Signer signer;
		try {
			signer = new HmacSHA256Signer(ISSUER, null, SIGNING_KEY.getBytes());
		} catch (InvalidKeyException e) {
			throw new RuntimeException(e);
		}

		//Configure JSON token
		JsonToken token = new net.oauth.jsontoken.JsonToken(signer);
		token.setAudience(AUDIENCE);
		token.setIssuedAt(new org.joda.time.Instant(cal.getTimeInMillis()));
		token.setExpiration(new org.joda.time.Instant(cal.getTimeInMillis() + 1000L * 60L * 60L * 24L * durationDays));

		//Configure request object, which provides information of the item
		JsonObject request = new JsonObject();
		request.addProperty("userId", userId);

		JsonObject payload = token.getPayloadAsJsonObject();
		payload.add("info", request);

		try {
			return token.serializeAndSign();
		} catch (SignatureException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Verifies a json web token's validity and extracts the user id and other information from it. 
	 * @param token
	 * @return
	 * @throws SignatureException
	 * @throws InvalidKeyException
	 */
	public static TokenInfo verifyToken(String token)  
	{
		try {
			final Verifier hmacVerifier = new HmacSHA256Verifier(SIGNING_KEY.getBytes());

			VerifierProvider hmacLocator = new VerifierProvider() {

				@Override
				public List<Verifier> findVerifier(String id, String key){
					return Lists.newArrayList(hmacVerifier);
				}
			};
			VerifierProviders locators = new VerifierProviders();
			locators.setVerifierProvider(SignatureAlgorithm.HS256, hmacLocator);
			net.oauth.jsontoken.Checker checker = new net.oauth.jsontoken.Checker(){

				@Override
				public void check(JsonObject payload) throws SignatureException {
					// don't throw - allow anything
				}

			};
			//Ignore Audience does not mean that the Signature is ignored
			JsonTokenParser parser = new JsonTokenParser(locators,
					checker);
			JsonToken jt;
			try {
				jt = parser.verifyAndDeserialize(token);
			} catch (SignatureException e) {
				throw new RuntimeException(e);
			}
			JsonObject payload = jt.getPayloadAsJsonObject();
			TokenInfo t = new TokenInfo();
			String issuer = payload.getAsJsonPrimitive("iss").getAsString();
			String userIdString =  payload.getAsJsonObject("info").getAsJsonPrimitive("userId").getAsString();
			if (issuer.equals(ISSUER) && !StringUtils.isBlank(userIdString))
			{
				t.setUserId(new ObjectId(userIdString));
				t.setIssued(new DateTime(payload.getAsJsonPrimitive("iat").getAsLong()));
				t.setExpires(new DateTime(payload.getAsJsonPrimitive("exp").getAsLong()));
				return t;
			}
			else
			{
				return null;
			}
		} catch (InvalidKeyException e1) {
			throw new RuntimeException(e1);
		}
	}


}

public class TokenInfo {
	private ObjectId userId;
	private DateTime issued;
	private DateTime expires;
	public ObjectId getUserId() {
		return userId;
	}
	public void setUserId(ObjectId userId) {
		this.userId = userId;
	}
	public DateTime getIssued() {
		return issued;
	}
	public void setIssued(DateTime issued) {
		this.issued = issued;
	}
	public DateTime getExpires() {
		return expires;
	}
	public void setExpires(DateTime expires) {
		this.expires = expires;
	}
}

This is based on code here: https://developers.google.com/wallet/instant-buy/about-jwts And Here: https://code.google.com/p/wallet-online-sample-java/source/browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa

Solution 5 - Java

IETF has suggested jose libs on it's wiki: http://trac.tools.ietf.org/wg/jose/trac/wiki

I would highly recommend using them for signing. I am not a Java guy, but seems like jose4j seems like a good option. Has nice examples as well: https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

> Update: jwt.io provides a neat comparison of several jwt related > libraries, and their features. A must check!

I would love to hear about what other java devs prefer.

Solution 6 - Java

I found this to be small and complete https://github.com/auth0/java-jwt

Solution 7 - Java

This page keeps references to implementations in various languages, including Java, and compares features: http://kjur.github.io/jsjws/index_mat.html

Solution 8 - Java

If you only need to parse unsigned unencrypted tokens you could use this code:

boolean parseJWT_2() {
	String authToken = getToken();
    String[] segments = authToken.split("\\.");
    String base64String = segments[1];
    int requiredLength = (int)(4 * Math.ceil(base64String.length() / 4.0));
    int nbrPaddings = requiredLength - base64String.length();
    
    if (nbrPaddings > 0) {
        base64String = base64String + "====".substring(0, nbrPaddings);
    }
    
    base64String = base64String.replace("-", "+");
    base64String = base64String.replace("_", "/");
    
    try {
    	byte[] data = Base64.decode(base64String, Base64.DEFAULT);
    
    	String text;
		text = new String(data, "UTF-8");
	    tokenInfo = new Gson().fromJson(text, TokenInfo.class);
	} catch (Exception e) {
		e.printStackTrace();
		return false;
	}

    return true;
}

Solution 9 - Java

https://github.com/networknt/jsontoken

This is a fork of original google jsontoken

It has not been updated since Sep 11, 2012 and depends on some old packages.

What I have done:

Convert from Joda time to Java 8 time. So it requires Java 8.
Covert Json parser from Gson to Jackson as I don't want to include two Json parsers to my projects.
Remove google collections from dependency list as it is stopped long time ago.
Fix thread safe issue with Java Mac.doFinal call.

All existing unit tests passed along with some newly added test cases.

Here is a sample to generate token and verify the token. For more information, please check https://github.com/networknt/light source code for usage.

I am the author of both jsontoken and Omni-Channel Application Framework.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarius ManastireanuView Question on Stackoverflow
Solution 1 - JavaLes HazlewoodView Answer on Stackoverflow
Solution 2 - JavaMarius ManastireanuView Answer on Stackoverflow
Solution 3 - JavaAlireza FattahiView Answer on Stackoverflow
Solution 4 - JavaMarquezView Answer on Stackoverflow
Solution 5 - JavaPriyeshjView Answer on Stackoverflow
Solution 6 - JavamfirryView Answer on Stackoverflow
Solution 7 - JavaHans Z.View Answer on Stackoverflow
Solution 8 - JavaAnton DuzenkoView Answer on Stackoverflow
Solution 9 - JavaSteve HuView Answer on Stackoverflow