DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Securing Spring Boot Microservices with JSON Web Tokens (JWT)
  • Streamlining Event Data in Event-Driven Ansible
  • Dynamic Web Forms In React For Enterprise Platforms
  • Unlocking Oracle 23 AI's JSON Relational Duality

Trending

  • Strategies for Securing E-Commerce Applications
  • Simplifying Multi-LLM Integration With KubeMQ
  • Optimizing Serverless Computing with AWS Lambda Layers and CloudFormation
  • Endpoint Security Controls: Designing a Secure Endpoint Architecture, Part 2
  1. DZone
  2. Coding
  3. Languages
  4. From JSON Web Token to Single Sign-On Part 1: Creating the Token

From JSON Web Token to Single Sign-On Part 1: Creating the Token

This is the first entry in a series of articles that offer a solution to Single Sign-on using the JSON Web Token (JWT) standard.

By 
Basel Almustafa user avatar
Basel Almustafa
·
Sep. 13, 15 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
50.6K Views

Join the DZone community and get the full member experience.

Join For Free

This is the first entry in a series of articles that offer a method for building Single Sign-on using the JSON Web Token (JWT) standard1. In this entry, you will learn how to implement an authentication service that generates encrypted tokens based on user credentials. This encrypted token can be used to access other sites sharing the same top level domain. It is assumed that each user has a single account, which is used to access multiple sites. If you are not familiar with JWT, I highly recommend reading “The Anatomy of a JSON Web Token.”2

The Authentication Service

The primary goal of the authentication service is to perform the actual authentication of users and to initiate the creation of the token. A user would send an email address and password to a predefined URL, such as https://dzone.com/services/auth, using the POST method over HTTPS. To keep things simple, these credentials would be handled by a servlet’s doPost() method.

@WebServlet("/auth")
public class AuthServlet extends HttpServlet {

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// retrieve the email and password from the request
String email = request.getParameter("email");
String password = request.getParameter("password");

// authenticate user
User user = new User(email, password);
// the authenticate() method code was omitted because it’s domain specific
boolean authenticated = new AuthService().authenticate(user);

if(authenticated) {
	String token = null;
	TokenService tokenService = new TokenService();
	try {
		token = tokenService.generateToken(user);
	} 
	catch (NoSuchAlgorithmException | JOSEException | IOException e) {
// TODO handle exceptions
	}
// TODO store token and send response
} 
else {
	response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
	return;
}
}
}

At this point, the token is ready for storage and the response should have been sent. The details of token storage are discussed next.

Generating an Encrypted JWT

As highlighted in the above code, token generation is handled by the TokenService class. Its implementation is based on the Nimbus JOSE + JWT3 library, which supports both the JSON Web Signature (JWS) and JSON Web Encryption (JWE) standards. To use these two standards, you would need a key to sign and encrypt the token. The code snippet below shows you how to generate a secret key using the KeyGenerator4 class from javax.crypto package. Once the key is generated, its primary encoding format is obtained. This format is needed for signing and encryption of the token.

// generate 256-bit AES key
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(256);
SecretKey key = generator.generateKey();

// get the key in encoded format
byte[] encodedKey = key.getEncoded();

Now that the key is ready, it is time to create the token. This can be done by defining a set of claims that form the payload of the token.

public class TokenService {

private static final long HOUR = 3600 * 1000;
public String generateToken(User user) throws NoSuchAlgorithmException, JOSEException, IOException{
String encryptedToken = null;
        // Prepare JWT with claims set
        Date issueDate = new Date();
        Date expireDate = new Date(issueDate.getTime() + 12 * HOUR);

        JWTClaimsSet claims = new JWTClaimsSet();
        claims.setSubject("authentication token");
        claims.setIssueTime(issueDate);
        claims.setExpirationTime(expireDate);
        claims.setIssuer("https://dzone.com");
        claims.setCustomClaim("email", user.getEmail());
        claims.setCustomClaim("password", user.getPassword());
        // the implementation of getEncodedKey() is similar to the code snippet above
        byte[] encodedKey = new KeyService().getEncodedKey();

// TODO create a signed and encrypted JWT

return encryptedToken;

}
}

The generateToken() methods starts by defining six claims, four of which are used to verify the validity of the token while the remaining two are application specific. These two custom claims are used to hold the email address and password of the user. This set of claims is used in the following code snippet, which is part of the generateToken() method, to create the signed and encrypted token.

// create a signed and encrypted JWT
// the implementation of getEncodedKey() is shown above as a code snippet
byte[] encodedKey = new KeyService().getEncodedKey();
JWSSigner signer = new MACSigner(encodedKey);

// create a token based on the SHA-256 hash algorithm
SignedJWT signedToken = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claims);
signedToken.sign(signer);

// create JWE header that directly uses 256 bit symmetric key for block encryption (AES)
JWEHeader jweHeader = new JWEHeader.Builder( JWEAlgorithm.DIR, EncryptionMethod.A256GCM).contentType("JWT").build();

// create JWE object with the signed token as the payload
JWEObject jweObject = new JWEObject(jweHeader, new Payload(signedToken));

// encryption the token and serialize it to get its compact form
jweObject.encrypt(new DirectEncrypter(encodedKey));
encryptedToken = jweObject.serialize();

This compact form of the token is used to verify user identity on sites sharing the same top level domain. The next section briefly discusses the approach used to share the token between the sites.

Storage of the Encrypted JWT

As previously mentioned, in the doPost() method under “The Authentication Service” section, the token would need to be stored and sent back as part of the response. This is needed because the client who invoked the authentication service would need the token in future communication with other sites. The approach used here to store the token by using a secure cookie. This cookie would be sent by the browser with each request to any of the sites sharing the same top level domain. Here is the code to create the secure cookie:

// create a secure cookie to hold the token
Cookie cookie = new Cookie("jwt-auth-token", token);
// ensure that the cookie is sent over HTTPS only
cookie.setSecure(true);
// ensure that the cookie cannot be accessed from JavaScript
cookie.setHttpOnly(true);
// a negative value means that the cookie is not stored persistently and will be deleted when the Web browser exits
cookie.setMaxAge(-1);
// the domain name within which this cookie is visible; form is according to RFC 2109
cookie.setDomain(".dzone.com");
// make the cookie visible to all pages
cookie.setPath("/");

// add the cookie to the response and return from the doPost() method
response.addCookie(getCookie(token));
response.setStatus(HttpServletResponse.SC_CREATED);
return;

What is Next?

In the next entry of the series, you will learn how to retrieve the token, verify its content, and access the claim set it holds.

References

  1. JSON Web Token (JWT) RFC 7519 https://tools.ietf.org/html/rfc7519
  2. The Anatomy of a JSON Web Token https://scotch.io/tutorials/the-anatomy-of-a-json-web-token
  3. Nimbus JOSE + JWT library http://connect2id.com/products/nimbus-jose-jwt
  4. KeyGenerator API http://docs.oracle.com/javase/7/docs/api/javax/crypto/KeyGenerator.html
JSON Web Service

Opinions expressed by DZone contributors are their own.

Related

  • Securing Spring Boot Microservices with JSON Web Tokens (JWT)
  • Streamlining Event Data in Event-Driven Ansible
  • Dynamic Web Forms In React For Enterprise Platforms
  • Unlocking Oracle 23 AI's JSON Relational Duality

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!