2

I am using Grails 3.1.4 together with the Spring Security Rest Plugin 2.0.0.M2 for implementing a single page app with AngularJS. Login and validation is working perfectly fine, but when I call logout I get a 404 error.

When debugging, I get an exception in the plugin RestLogoutFilter:

try {
    log.debug "Trying to remove the token"
    tokenStorageService.removeToken accessToken.accessToken
} catch (TokenNotFoundException tnfe) {
    servletResponse.sendError HttpServletResponse.SC_NOT_FOUND, "Token not found"
}

Exception:

grails.plugin.springsecurity.rest.token.storage.TokenNotFoundException: 
Token eyJh... cannot be removed as this is a stateless implementation

Calling

tokenStorageService.loadUserByToken(accessToken.accessToken)

works, so the token certainly is in the tokenStorage.

My Spring Security configuration is

grails.plugin.springsecurity.userLookup.userDomainClassName = 'myapp.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'myapp.UserRole'
grails.plugin.springsecurity.authority.className = 'myapp.Role'
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
grails.plugin.springsecurity.rest.login.usernamePropertyName='email'
grails.plugin.springsecurity.rest.token.storage.gorm.usernamePropertyName='email'
grails.plugin.springsecurity.rest.logout.endpointUrl = '/api/logout'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
        [pattern: '/',               access: ['permitAll']],
        [pattern: '/error',          access: ['permitAll']],
        [pattern: '/index',          access: ['permitAll']],
        [pattern: '/index.gsp',      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: '/api/logout',     access: ['isAuthenticated()']]
]

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']
]

Is there an error in my config or any other thing wrong?

Tobi
  • 2,001
  • 2
  • 27
  • 49

1 Answers1

3

Found the answer minutes after asking the question.

The Spring Security Rest plugin documentation states:

Logout is not possible when using JWT tokens (the default strategy), as no state is kept in the server. If you still want to have logout, you can provide your own implementation by creating a subclass of JwtTokenStorageService and overriding the methods storeToken and removeToken. Then, register your implementation in resources.groovy as tokenStorageService.

However, a more rational approach would be just to remove the token from the client (eg, browser's local storage) and let the tokens expire (they will expire anyway, unlike with other storages like Memcached or Redis where they get refreshed on every access).

So just deleting the token on the client is sufficient if one is using JWT for authorization.

Tobi
  • 2,001
  • 2
  • 27
  • 49
  • Do you have any tutorials that show how to implement the first suggestion; "If you still want to have logout, you can provide your own implementation by creating a subclass of JwtTokenStorageService and overriding the methods storeToken and removeToken. Then, register your implementation in resources.groovy as tokenStorageService." – Pila Apr 05 '18 at 10:11
  • No, I have not, but the basic idea is easy. You create a class like `CustomJwtTokenStorageService` and derive it from `JwtTokenStorageService`. Then you implement implement some store and deletion mechanism and register your new service in the resources.groovy as described here https://docs.grails.org/latest/guide/spring.html . The important thing to understand is, that your JWT token is not actually saved on your server, so it should not be necessary, to implement a logout mechanism this way and deletion of the token on the client should be sufficient. – Tobi Apr 05 '18 at 10:47