Spring Boot and OAuth2 with JDBC

How can we implement OAuth2 with Spring Boot?

This blog post assumes that you know what is the OAuth2 protocol and how it works. If you do not know, I advise you to do some research and come back later as you may not fully understand it from reading this blog post.

There are several examples online but most of them are using some sort of in memory database. If your system is going to production you, most likely, do not want to use an in memory database to store the user tokens when you have multiple server instances. You want some sort of a central location (or distributed with some level of consistency) where you’ll be storing the OAuth data for each user account. The easiest is using a SQL database and this is going to be our example.

First, it’s time to setup the database tables for the OAuth2, therefore we need the following tables:

  • oauth_client_details
  • oauth_client_token
  • oauth_access_token
  • oauth_refresh_token
  • oauth_code
  • oauth_approvals
  • ClientDetails

As we are using Spring Boot we can create a file named schema.sql  in the resources folder with our schema definition. On boot time, Spring Boot will detect the file and will run it against our selected database – quite handy isn’t it?

When the database schema is all set, we need to populate the oauth_client_details table. Again, Spring Boot helps making our life easier. To do so, we just need to create a file named data.sql  and, as with the schema.sql , Spring Boot on boot time will pick the file and run in against our database.

At this point we have everything related with the SQL database ready to go.

Now, to the coding. We need to add the @EnableResourceServer annotation to our Spring application, and we do it as easy as:

@EnableResourceServer
@SpringBootApplication
public class OauthExampleApplication {

   public static void main(String[] args) {
      SpringApplication.run(OauthExampleApplication.class, args);
   }
}

The next step is to configure our DataStore  and our TokenStore . To do so we create an AppConfig.class  (wich is a configuration class) and define it there (you can define it somewhere else as long as you set the @Bean  annotation to both methods).

@Configuration
public class AppConfig {
    
    @Value("${spring.datasource.url}")
    private String datasourceUrl;
    
    @Value("${spring.database.driverClassName}")
    private String dbDriverClassName;
    
    @Value("${spring.datasource.username}")
    private String dbUsername;
    
    @Value("${spring.datasource.password}")
    private String dbPassword;
    
    @Bean
    public DataSource dataSource() {
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();
        
        dataSource.setDriverClassName(dbDriverClassName);
        dataSource.setUrl(datasourceUrl);
        dataSource.setUsername(dbUsername);
        dataSource.setPassword(dbPassword);
        
        return dataSource;
    }
    
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource());
    }
}

As we can see above, our TokenStore  is defined by a JdbcTokenStore  which extends TokenStore . We also pass the DataSource  to the JdbcTokenStore and therefore we let the application know we are using the specified DataSource  to store all our OAuth2 data. On the other hand, the DataSource  specifies that we are using a SQL database. See how it all interconnects here? Perfect.

But this is not enough. Now we need to wired everything up, the database – the authorization server – Spring Boot application. The authorization server will be the bridge here. So, lets start with it. We create a class (AuthServerOAuth2Config) to extend AuthorizationServerConfigurerAdapter . Then we need to override configure(ClientDetailsServiceConfigurer clients) , configure(AuthorizationServerSecurityConfigurer security) and configure(AuthorizationServerEndpointsConfigurer endpoints)  methods to wire everything up.

@EnableAuthorizationServer
@Configuration
public class AuthServerOAuth2Config extends AuthorizationServerConfigurerAdapter {
    
    private final AuthenticationManager authenticationManager;
    private final AppConfig appConfig;
    
    @Autowired
    public AuthServerOAuth2Config(AuthenticationManager authenticationManager, AppConfig appConfig) {
        this.authenticationManager = authenticationManager;
        this.appConfig = appConfig;
    }
    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(appConfig.dataSource());
    }
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        /*
         * Allow our tokens to be delivered from our token access point as well as for tokens
         * to be validated from this point
         */
        security.checkTokenAccess("permitAll()");
    }
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)
                .tokenStore(appConfig.tokenStore()); // Persist the tokens in the database
    }
}

And now we have OAuth2 with JDBC implemented. We can start generating some tokens by making POST requests to our server at /oauth/token with the Authorization type, headers and body (form data) properly set up.

Optionally we may want to create an endpoint that will return all information for the user calling it. To do so, we create the PrincipalResource.class  as shown below

@RestController
@RequestMapping(path = "/account")
public class PrincipalResource {

    @RequestMapping(method = RequestMethod.POST)
    public Principal oauth(Principal principal) {
        /*
         * Translate the incoming request, which has an access token
         * Spring security takes the incoming request and injects the Java Security Principal
         * The converter inside Spring Security will handle the to json method which the Spring Security
         * Oauth client will know how to read
         *
         * The @EnableResourceServer on the application entry point is what makes all this magic happen.
         * If there is an incoming request token it will check the token validity and handle it accordingly
         */
        return principal;
    }
}

Now, every time someone makes sends a GET request to /account with a valid token we return all known information about that person.

Enjoy your application server with support for OAuth2 using JDBC/SQL database.

PS; All source code can be found on my GitHub repository.

CouchDB with RxJava – ChangesFeed got even sweeter

CouchDB is a real time database, where data is stored as JSON documents. One particular thing I like in CouchDB is their ChangesFeed. I like the idea of having a real time feed with all the changes in the data I’m interested in.

There are different ways to access the ChangesFeed and I wont go into details but mostly you can either poll the ChangesFeed for changes, which I find archaic and not really up to the current standards/technologies, or you can use the Continuous Changes. As stated in the CouchDB docs, a continuous feed stays open and connected to the database until explicitly closed and changes are sent to the client as they happen, i.e. in near real-time. This is neat but it can be neater with RxJava.

So, I thought: why not observe the ChangesFeed and emit an event as soon as there is a new item in it? Unfortunately the Java driver for CouchDB (Ektorp) does not have RxJava support. Still, it shouldn’t be that difficult to implement some kind of an observable into the ChangesFeed.

After lurking around Ektorp source code I found out that ChangesFeed is an interface that is implemented by ContinuousChangesFeed. Again, inspecting CountinuousChangesFeed class I see a

private final BlockingQueue changes = new LinkedBlockingQueue(100);

and… bingo!

I just need to observe this LinkedBlockingQueue for changes and emit them!

So, I created a PublishSubject<StdDocumentChange> that will emit all new items added into the LinkedBlockingQueue. PublishSubject<StdDocumentChange> will also provide an Observable to whom we can subscribe for changes. Sweet. This is all we need to add into the ContinuousChangesFeed class:

// Declare our PublishSubject and create it 
private final PublishSubject onAdded = PublishSubject.create();
// Call the PublishSubjsect's onNext() when there is a new item in the LinkedBlockingQueue 
private void handleChange(String line) throws IOException, InterruptedException, JsonParseException, JsonMappingException { 
    StdDocumentChange stdDocumentChange = new StdDocumentChange(OBJECT_MAPPER.readTree(line)); 
    changes.put(stdDocumentChange); 
    onAdded.onNext(stdDocumentChange); 
}

// Provide an Observable to whom we can subscribe for events 
public Observable onAdded() { 
    return onAdded; 
}

To consume the changes we just need to subscribe to the Observable provided by the PublishSubject we defined above. We can do that this way:

// Get a reference to the ChangesFeed 
ContinuousChangesFeed continuousChangesFeed = (ContinuousChangesFeed) couchDBQuery.changesFeed(myCouchDd.getDbConnector());

// Subscribe! - Remember, onAdded() returns an Observable. 
subscription = continuousChangesFeed.onAdded()
        .subscribe(new Action1() {
            @Override
            public void call(StdDocumentChange document) {
                System.out.println("Received: " + document);
            }
        });

Or with Java 8 Lambdas

subscription = continuousChangesFeed.onAdded()
        .subscribe((StdDocumentChange document) -> {
            System.out.println("Received: " + document);
        });

I’ve forked Ektorp and applied this changes. You can find the forked repository with the RxJava implementation here. Either way I’ll soon submit a pull request to Ektorp repository and I’ll update this post with the outcome.

I’ve also created a small app that observes the ChangesFeed. In the app you can insert documents into a CouchDB database and observe the ChangesFeed. To run the app you’ll need to set (in the code) the CouchDB server ip address, port and database name. You can get the source code from Github here.

 

EDIT: The pull request was rejected as: This feature might be nice, but it does not justify another dependency on a quite big lib as RxJava. I would rather see a complete Rx’fied CouchDb driver, that is based on non-blocking code from the ground up.

Link to the pull request.