History of a bug

SpringBoot 2, OAUTH 2 and tokenStore

Rédigé par gorki Aucun commentaire

Problem :

Following the previous post (this one and this one) I configured a Authorization and Resource server on a a same JVM.

All was working well in my local machine, but when I send the springboot on the server, I get an "Invalid access token". The authorization request was accepted, I get an access token but it was refused by Resource server.


Solution :

I activate remote DEBUG, perform tests (I also had a reverse proxy but that's was not the problem). The issue was due to the tokenStore which :

  • on my local machine was the same instance
  • on the server was two different instance

In fact depending on the bean initialization order, the token store could be shared or not according to optional Autowire field of the authorization and resource server. If not available at init time, it could use a local instance.

So here is my updated configuration :

My AuthorizationServer is now :

package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    public TokenStore tokenStore;

    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(new MyClientDetailsService());

    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

And my resource server :

package com.hexagon.hpa.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;

public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "RESSOURCE_ID";

    TokenStore tokenStore;

    public void configure(ResourceServerSecurityConfigurer resources) {


    public void configure(HttpSecurity http) throws Exception {
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());


A simple configurer :

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

public class TokenStoreProvider {

    public TokenStore tokenStore() {
        return new InMemoryTokenStore();


SpringBoot 2, OAUTH 2 and client_credentials in POST parameters

Rédigé par gorki Aucun commentaire

Problem :

Edited : due to a bug, see also (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)

I try to implements client credentials OAUTH flow for a server which is resource and authentication server. (Goody summary here : https://www.slideshare.net/halyph/oauth2-and-spring-security)

There is plenty of posts on how to make an oauth 2 authentication server, (like authentication code flow  less with client_credentials mode...

And in these examples :

But if I easily found how to perform this kind of request : POST + BasicAuth(client_id/client_secret), I wasn't able to do :

POST + optional BasicAuth + client_id/client_secret in post parameters

Solution :

I activate DEBUG on spring security and see that filter chains do not have UsernamePasswordAuthenticationFilter, I plan to add the filter in websecurity as in some examples but it was not working.

After a lot of unsuccessful tries, I finally understand that I have to add a kind of UsernamePasswordAuthenticationFilter on OAUTH2 filter chain and not on the others (yes, there is multiple security filter chain....)

Going back to origins, I check AuthorizationServerConfigurerAdapter override method and ... eurêka !

As simple as add a




method... So simple, so hard to find.

But my AuthorizationServer is now :

Due to a bug, the code is now in (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)

And a simple (for now) client detail service :

package com.example;

import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

import java.util.Arrays;

public class MyClientDetailsService implements ClientDetailsService {

    private static final String CLIENT_CREDENTIALS = "client_credentials";
    private static final String REFRESH_TOKEN = "refresh_token";
    private static final String SCOPE_READ = "read";
    private static final String SCOPE_WRITE = "write";
    private static final String TRUST = "trust";
    private static final int VALID_FOREVER = -1;

    private static final String CLIENT_ID = "my-client";
    // encoding method prefix is required for DelegatingPasswordEncoder which is default since Spring Security 5.0.0.RC1
    // you can use one of bcrypt/noop/pbkdf2/scrypt/sha256
    // you can change default behaviour by providing a bean with the encoder you want
    // more: https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-encoding
    static final String CLIENT_SECRET = "{noop}my-secret";

    public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException {
        if (s.equals(CLIENT_ID)) {
            BaseClientDetails client = new BaseClientDetails();
            client.setAuthorizedGrantTypes(Arrays.asList(CLIENT_CREDENTIALS, REFRESH_TOKEN));
            client.setScope(Arrays.asList(SCOPE_READ, SCOPE_WRITE, TRUST));
            return client;
        return null;


And my resource server :

Due to a bug, the code is now in (https://www.hoab.fr/springboot-2-oauth-2-and-tokenstore)

The CORS filter from (https://www.hoab.fr/springboot-2-oauth-2-options-and-cors) :

package com.example;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SimpleCorsFilter implements Filter {

    public SimpleCorsFilter() {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, content-type");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        } else {
            chain.doFilter(req, res);

    public void init(FilterConfig filterConfig) {

    public void destroy() {

And a protected resource :

package com.example;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

public class Metrics {

    String getToken() {
        return "OK";





Fil RSS des articles de ce mot clé