1. Overview

In the previous example, we have discussed about spring boot OAuth 2 authentication server configuration but it was storing token in-memory. Here is an explanation of Spring boot Oauth2 JDBC token store example:

Advantages of store token information in the database:

  • If multiple authentication servers used for load balancing at that time token store must be share which can be archive JDBC token store.
  • If authentication server needs to restart in this case in-memory token will be loss that problem can be solve using JDBC token store.

 2. Example

Spring boot OAuth2 JDBC token store example

Spring boot OAuth2 JDBC token store example

2.1 pom.xml

spring-boot-starter-jdbc requires to database configuration, mysql-connector-java drive for MySQL database connection

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>spring-boot-example</groupId>
    <artifactId>Spring-boot-Oauth2-JDBC-token-store-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <description>Spring boot Oauth2 JDBC token store example</description>
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>  <!--starter require for spring boot spring security-->
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>   <!--It contains database base related classes-->
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

    <!-- Package as an executable jar -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2 schema.sql

schema.sql file must be available insider resources folder so automatically schema will be created in the database. Or Also possible to execute the script manually.

create table if not exists oauth_access_token (
  token_id VARCHAR(255),
  token LONG VARBINARY,
  authentication_id VARCHAR(255) PRIMARY KEY,
  user_name VARCHAR(255),
  client_id VARCHAR(255),
  authentication LONG VARBINARY,
  refresh_token VARCHAR(255)
);

create table if not exists oauth_refresh_token (
  token_id VARCHAR(255),
  token LONG VARBINARY,
  authentication LONG VARBINARY
);

2.3 application.properties

application.properties contains database properties where tokens information will be store

spring.datasource.url=jdbc:mysql://localhost/demo_database
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
debug=true

2.4 SecurityOAuth2Configuration

JdbcTokenStore requires database source which will be used to store token related information. TokenStore bean will be passed to AuthorizationServerEndpointsConfigurer endpoints.

@EnableAuthorizationServer indicate that consider current server or service as authentication server or service

package com.javadeveloperzone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.JdbcTokenStore;

import javax.sql.DataSource;

/**
 * Created by JavaDeveloperZone on 04-08-2017.
 */
@Configuration
@EnableAuthorizationServer
public class SecurityOAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()")
                   .checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
               .withClient("javadeveloperzone")
               .secret("secret")
               .accessTokenValiditySeconds(2000)        // expire time for access token
               .refreshTokenValiditySeconds(-1)         // expire time for refresh token
               .scopes("read", "write")                         // scope related to resource server
               .authorizedGrantTypes("password", "refresh_token");      // grant type

    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
        endpoints.tokenStore(tokenStore());
    }
}

2.5 SecurityConfiguration

Spring Security-related configuration like user, role, and credential has been in-memory for the simple example.

package com.javadeveloperzone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * Created by JavaDeveloperZone on 09-12-2017.
 */
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/", "/login**")
                .permitAll()
                .anyRequest()
                .authenticated();
    }

    @Autowired      // here is configuration related to spring boot basic authentication
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()                                               // static users
            .withUser("zone1").password("mypassword").roles("USER")
            .and()
            .withUser("zone2").password("mypassword").roles("USER")
            .and()
            .withUser("zone3").password("mypassword").roles("USER")
            .and()
            .withUser("zone4").password("mypassword").roles("USER")
            .and()
            .withUser("zone5").password("mypassword").roles("USER");
    }
}

2.6 SpringBootApplication

package com.javadeveloperzone;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

/**
 * Created by JavaDeveloperZone on 19-07-2017.
 */

@org.springframework.boot.autoconfigure.SpringBootApplication
@ComponentScan({"com.javadeveloperzone"})

// Using a root package also allows the @ComponentScan annotation to be used without needing to specify a basePackage attribute
public class SpringBootApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootApplication.class, args);            // it wil start application
    }
}

2.7 Output:

Generate Token using http://localhost:8080/oauth/token

Spring boot OAuth2 JDBC token store example demo

Spring boot OAuth2 JDBC token store example demo

oauth_refresh_token contains refresh tokens information

Spring boot OAuth2 Refresh Token Table

Spring boot OAuth2 Refresh Token Table

oauth_access_token contains access token information

Spring boot OAuth2 Access Token Table

Spring boot OAuth2 Access Token Table

 

 

Was this post helpful?
Let us know, if you liked the post. Only in this way, we can improve us.
Yes
No

2 comments. Leave new

How can i add roles to dynamic user.

Hi Akanksha,

You can create custom UserServiceDetails to load dynamic load roles, Here is an example of OAuth2UserService : https://docs.spring.io/spring-security/site/docs/5.0.3.RELEASE/reference/htmlsingle/#oauth2login-advanced-map-authorities-oauth2userservice.

We will come back to you with example.

Thank you

Leave a Reply

Your email address will not be published. Required fields are marked *