Skip to content

Use JWT as Access Token

Wuyi Chen edited this page Apr 10, 2019 · 13 revisions

Overview

JSON Web Token (JWT) is a JSON-based open standard (RFC 7519) for creating access tokens. There are some facts about JWT:

  • Encoded into Base64.
  • The authorized entity can decrypt a JWT to JSON.
  • JWT allows you to add custom fields into JSON.

For changing your authentication eco-system to use JWT token, you need to do several things:


Configure the authentication service

Set dependencies

Besides the Spring Security library and the OAuth2 library, the Spring Security JWT library needs to be added.

build.gradle

dependencies {
    // Spring Security and OAuth2
    compile group: 'org.springframework.cloud',          name: 'spring-cloud-security'
    compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2',       version: '2.1.3.RELEASE'
	
    // Spring Security JWT
    compile group: 'org.springframework.security',       name: 'spring-security-jwt',          version: '1.0.0.RELEASE'

    // For storing credentials and roles in database
    compile group: 'org.springframework.boot',           name: 'spring-boot-starter-data-jpa', version: '1.5.0.RELEASE'
    compile group: 'org.springframework.boot',           name: 'spring-boot-autoconfigure',    version: '1.5.0.RELEASE'
    compile group: 'mysql',                              name: 'mysql-connector-java',         version: '5.1.38'
}

Add signing key

Like encrypting passwords in the config server, you need set up a symmetric encryption key by adding signing.key into the configuration of the authentication service. You can either add it to the local application.yml file or the remote authenticationservice.yml file if you moved the configuration into the config server.

application.yml

signing:
  key: 345345fsdfsf5345

authenticationservice.yml

signing.key: "345345fsdfsf5345"

Define the logic of creating, signing and translating JWT token

JWTTokenStoreConfig.java

@Configuration
public class JWTTokenStoreConfig {
    @Autowired
    private ServiceConfig serviceConfig;

    /**
     * Create a new JWT token store.
     * 
     * @return  The {@code TokenStore} object.
     */
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    /**
     * Generate token services.
     * 
     * <p>This method will use the Spring security’s default token services 
     * implementation which tokens will be generated as random UUID values.
     * 
     * @return  The {@code DefaultTokenServices} object.
     */
    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

    /**
     * Generate the converter for translating the token.
     * 
     * @return  The {@code JwtAccessTokenConverter} object with the signing 
     *          key.
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(serviceConfig.getJwtSigningKey());           // Set the signing key that will be used to sign your token (define in configuration)
        return converter;
    }

    /**
     * Create a new JWT token enhancer.
     * 
     * <p>The {@code JWTTokenEnhancer} class will help on adding custom fields 
     * into a JWT token. Currently, the organization Id field is added into 
     * the JWT token.
     * 
     * @return  The {@code TokenEnhancer} object.
     */
    @Bean
    public TokenEnhancer jwtTokenEnhancer() {
        return new JWTTokenEnhancer();
    }
}

Hook the authentication service with the logic of JWT token

JWTOAuth2Config.java

@Configuration
public class JWTOAuth2Config extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private DefaultTokenServices tokenServices;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private TokenEnhancer jwtTokenEnhancer;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter));   // Spring Security allows you to hook multiple token enhancers

        endpoints.tokenStore(tokenStore)                                                                  // The JWTTokenStoreConfig.tokenStore() will be injected in here
                .accessTokenConverter(jwtAccessTokenConverter)                                            // The JWTTokenStoreConfig.jwtAccessTokenConverter() will be injected in here
                .tokenEnhancer(tokenEnhancerChain)                                                        // The chain of token enhancers will be passed into the endpoint
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }
    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {                      // Define what client applications are registered with the service
        clients.inMemory()                                                                                // Store the application information in memory
                .withClient("eagleeye")                                                                   // Specify which client application will register
                .secret("thisissecret")                                                                   // Specify the secret which will be used to get the access token
                .authorizedGrantTypes("refresh_token", "password", "client_credentials")                  // Provide a list of the authorization grant types that will be supported by the service
                .scopes("webclient", "mobileclient");                                                     // Define the types of the client applications can get the access token from the service
    }
}
Clone this wiki locally