Search code examples
restgrailsspring-securityoauth

403 response on a "refresh_token" request with Spring Security Rest in a Grails 3 application


I'm having some trouble making a "refresh_token" request with Spring Security Rest in a Grails 3 application. I have an application with both a web front-end and some Rest endpoints, and everything else seems to be working fine. The web app behaves as expected and, when I make a login request via curl with

curl -i -X POST localhost:8080/api/login \
-H "Content-Type: application/json" \
-d '{"username":"johndoe", "password":"johndoepassword"}' 

I get back the expected response (I have truncated the tokens):

{
 "username":"johndoe",
 "roles":["ROLE_USER"],
 "token_type":"Bearer",
 "access_token":"eyJhbGciOiJIUzI1NiJ9.xxxxxx",
 "expires_in":3600,
 "refresh_token":"eyJhbGciOiJIUzI1NiJ9.xxxx"
}

In the actual application, I can add the access_token to the header and authenticate with no problem for the duration of the session. However, I get a 403 when I hit the "refresh token" endpoint with

curl -i -X POST localhost:8080/oauth/access_token \
-H "Content-Type: application/x-www-form-urlencoded"  \
-d "grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiJ9.xxxx" 

This all seems pretty straightforward in the docs, but I'm obviously doing something wrong. Here's what I think is the relevant portion of my config file:

grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    [pattern: '/error',          access: ['permitAll']],
    [pattern: '/login',          access: ['permitAll']],
    [pattern: '/login/**',          access: ['permitAll']],
    [pattern: '/oauth/**',          access: ['permitAll']],
    [pattern: '/user/register',          access: ['permitAll']],
    [pattern: '/user/register/**',          access: ['permitAll']],
    [pattern: '/user/submitRegistration',          access: ['permitAll']],
    [pattern: '/logoff',          access: ['permitAll']],
    [pattern: '/shutdown',       access: ['permitAll']],
    [pattern: '/assets/**',      access: ['permitAll']],
    [pattern: '/**/js/**',       access: ['permitAll']],
    [pattern: '/**/css/**',      access: ['permitAll']],
    [pattern: '/**/images/**',   access: ['permitAll']],
    [pattern: '/**/favicon.ico', access: ['permitAll']],
    [pattern: '/surveyAdmin/**',  access: ['ROLE_ADMIN']] ,
    [pattern: '/**',               access: ['ROLE_USER']]
]

grails.plugin.springsecurity.filterChain.chainMap = [
    [pattern: '/assets/**',      filters: 'none'],
    [pattern: '/**/js/**',       filters: 'none'],
    [pattern: '/**/css/**',      filters: 'none'],
    [pattern: '/**/images/**',   filters: 'none'],
    [pattern: '/**/favicon.ico', filters: 'none'],

    [
            pattern: '/api/**',
            filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter'
    ],

    [
            pattern: '/rest/**',
            filters: 'restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor'
    ],
    [pattern: '/**',             filters: 'JOINED_FILTERS']
]

Can anyone suggest a way through here?

Thanks, Alex


Solution

  • As so often happens, I found the answer shortly after posting the question. I'm using a custom user class that implements org.springframework.security.core.userdetails.UserDetails but does not extend org.springframework.security.core.userdetails.User. The plugin assumes the principal can be cast to a "User" object, which was causing the user lookup/token generation to fail. Either changing my custom class to extend User or overriding the refreshToken method in the plugin to accept my custom user class got things working.