Spring Boot OAuth2 JWT
In this article, will learn how to implement JSON Web Token (JWT) as OAuth Access Token in Spring Boot. It's recommended to go over JWT basic, OAuth2 basic and it's grant types, as Password Grant Type, Client Credentials Grant Type.
Spring Boot Security - OAuth 2 Tutorial :
What is JWT (JSON Web Token)
JSON Web Token (JWT) is an open standard (RFC 7519) that specifies a compact and self-contained way of transmitting information securely as a JSON object between parties. This information can be verified and trusted as it has been digitally signed. It can also hold all the user's claim, like authorization information, so that the service provider does not need to access the database to validate user roles and permissions for each request; data is extracted from the token.
You can check benefits of using JWT Token as OAuth Token Over OAuth Default Token.
Will modify Client Credentials Grant Type example and update the code to implement JWT (JSON Web Token).
Generate Keystore
What is Java Keystore (.jks)?
A Java Keystore (.jks) is a repository for authorization certificates or public key certificates, and is often used by Java-based applications for encryption, authentication, and serving over HTTPS (SSL). Data/Entries are protected by a keystore password.
Syntax
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650 -storepass password
- genkeypair: It generates a key pair.
- alias: It provides alias name for the generated keystore.
- keyalg: Uses cryptographic algorithm to generate the key pair.
- keysize: Provision to define size of the key. We have used 2048 bits, however 4096 would be a better option for production.
- storetype: Type of keystore.
- keystore: Name of the keystore.
- validity: Validity number of days.
- storepass: A password for the keystore.
For generating JWT tokens, we need a key pair. Let's open the command prompt and execute the below command to generate keystore file with a keypair. Provide all the information required to generate certificate. In this example we have given the password as "pass123".
keytool -genkey -alias techgeeknextCert -storetype jks -keyalg RSA -keysize 2048 -keystore techgeeknextkeystore.jks
It will create certificate at D drive, as shown below:
Copy the generated techgeeknextkeystore.jks into src/main/resources
Authorization Server Config to Configure JWT keystore
@EnableAuthorizationServer annotation enables Spring Boot OAuth2. Define this Authorisation server to produce JWT tokens. This is achieved by defining a JwtTokenStore and pass it to AuthorizationServerEndpointsConfigurer.
Inject tokenstore() and accessTokenConverter() into AuthorizationServerEndpointsConfigurer.
JwtAccessTokenConverter extends Object implements TokenEnhancer, AccessTokenConverter, InitializingBean. JwtAccessTokenConverter is the helper that translates between JWT encoded token values and OAuth authentication information (in both directions). Also acts as a TokenEnhancer when tokens are granted.
We are modifying example of Client Credentials Grant Type to apply JWT changes. Open AuthorizationServerConfiguration.java and make below changes.
package com.techgeeknext.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("techgeeknextClient")
.authorizedGrantTypes("client_credentials")
.secret(encoder().encode("pass123"))
.scopes("user_info", "read", "write")
.redirectUris("http://localhost:8083/techgeeknext/login/oauth2/code/techgeeknextclient")
.autoApprove(false);
}
@Autowired
private AuthenticationManager authenticationManager;
/*** Start- JWT changes ***/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
// inject tokenstore() and accessTokenConverter() into AuthorizationServerEndpointsConfigurer
.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
final KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(
new ClassPathResource("techgeeknextkeystore.jks"), "pass123".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("techgeeknextCert"));
return converter;
}
/*** End- JWT changes ***/
@Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
Take a look at our suggested posts:
Testing OAuth JWT Access Token
- Get the JWT access token by making a POST request to http://localhost:8083/techgeeknext/oauth/token , provide the client_id and client_secret in the Basic Auth header.
- Provide grant_type as client_credentials.
- Now, to access the resource end point, pass the above JWT access token in Authorization Bearer.
- You can also check the JWT token information by using http://localhost:8083/techgeeknext/oauth/check_token
Now, you can notice, it has generated JWT token as in the form of
a
.b
.c
which represent
header
.payload
.signature
You can put the generated JWT token in https://jwt.io/
to see Header, Payload and Verify Signature.
Download Source Code
The full source code for this article can be found on below.Download it here - OAuth2 with JWT Access Token