(Quick Reference)

Spring Security REST Plugin - Reference Documentation

Authors: Alvaro Sanchez-Mariscal

Version: 1.4.0

1 Introduction to the Spring Security REST plugin

The Spring Security REST Grails plugin allows you to use Spring Security for a stateless, token-based, RESTful authentication.

This plugin depends on Spring Security Core 2.x. Make sure your application is compatible with that version first. There is a feature request, that may be addressed in the future if there is enough community interest / love :)

The default behaviour of Spring Security is to store the authenticated principal in the HTTP session. However, in a RESTful scenario, we need to make sure our server is stateless.

If you are writing an API that will be used by other programs, you can use OAuth for this. But if you are exposing your API for a front-end Javascript client to implement a Single Page Interface, OAuth is not an option, specially if you want to authentication end users against your own user backend (eg: LDAP). In this case, a token-based authentication may be a more suitable implementation, like the following:

  1. The client application requests and endpoint that requires authentication, so the server responds with a 401 response.
  2. The client redirects the user to the login form.
  3. The user enter credentials, and the client sends a request to the authentication endpoint. The server validates credentials, and if valid, generates, stores and sends back a token to the client.
  4. The client then stores the token internally. It will be sent on every API method request.
  5. The client sends again a request to the protected resource, passing the token as an HTTP header.
  6. The server validates the token, and if valid, executes the actual operation requested.

As per the REST definition, the client is transferring its state on every request so the server is truly stateless. The approach to store tokens on the server is just an alternative to use HTTP basic authentication (see FAQ) (so credentials are not passed on every request). It also helps to perform the validation step (#5 in the diagram) faster, because the tokens, and the associated principal information may be cached. Finally, storing tokens gives you the chance to decide about expiration strategies.

More information about this strategy can be found on this post by James Ward.

This plugin helps you to wire your existing Spring Security authentication mechanism, provides you with ready-to-use token generation strategies and comes prepackaged with Memcached, GORM and Grails Cache support for token storage.

Release History

2 What's new in 1.4?

Full compatibility with Spring Security core.

Up to previous releases, this plugin was overriding "stateful" Spring Security core beans, to ensure a stateless behaviour. After some users reported issues integrating this plugin with existing installations, version 1.4 now follows a more friendly approach.

A new chapter has been created explaining how to configure the filter chains appropriately.

RFC 6750 Bearer Token support by default

Now, the token validation and rendering aligns with the RFC 6750 Bearer Token spec. If you want to keep the old behaviour, simply disable it by setting grails.plugin.springsecurity.rest.token.validation.useBearerToken = false

Credentials are extracted from JSON by default

It makes more sense in a REST application. The old behaviour can still be used by using the corresponding configuration property.

Anonymous access is allowed

In case you want to enable anonymous access (read: not authenticated) to certain URL patterns, you can do so. Take a look at the new chapter in the documentation.

Other minor changes

  • Upgraded dependencies:
    • spring-security-core:2.0-RC3.
    • cors:1.1.6.

3 Configuration

Once the plugin is installed, the minimum configuration is to select what token storage strategy do you want to use:
  1. Grails Cache.
  2. Memcached
  3. GORM.
  4. Provide your own: implement TokenStorageService and register it in resources.groovy as tokenStorageService

All the other features can be used out-of-the-box with the default values, but please make sure you read the entire plugin documentation to understand how they work and how can they be configured.

Plugin configuration

This plugin depends on Spring Security Core 2.x. Make sure your application is compatible with that version first.

This plugin is compatible by default with Spring Security core traditional, form-based authentication. The important thing to remember is: you have to separate the filter chains, so different filters are applied on each case.

The stateless, token-based approach of this plugin is incompatible with the HTTP session-based approach of Spring Security, core, so the trick is to identify what URL patterns have to be stateless, and what others have to be stateful (if any).

To configure the chains properly, you can use the grails.plugin.springsecurity.filterChain.chainMap property:

grails.plugin.springsecurity.filterChain.chainMap = [
    '/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter',  // Stateless chain
    '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'                                          // Traditional chain
]

To understand this syntax, please read the Spring Security Core documentation. Long story short: JOINED_FILTERS refers to all the configured filters. The minus (-) notation means all the previous values but the neglected one.

So the first chain applies all the filters except the stateful ones. The second one applies all the filters but the stateless ones.

Make sure that the stateless chain applies not only to your REST controllers, but also to the URL's where this plugin filters are listening: by default, /api/login for authentication, /api/logout for logout and /api/validate for token validation.

The difference is that, in a traditional form-based authentication, Spring Security will respond with an HTTP 302 redirect to the login controller. That doesn't work for an API, so in the stateless approach, an HTTP 401 response will be sent back.

4 Authentication Endpoint

The authentication filter uses the default authenticationManager bean, which in turn uses all the registered authentication providers. See the Spring Security Core guide for more information about how to define your own providers. Note that you can easily plug any Spring Security sub-plugin (like the LDAP one) to use a different authentication strategy.

If the authentication is successful, a token generator is used to generate a token, and a token storage implementation is used to store the token. Finally, the JSON response sent back to the client is rendered by a restAuthenticationTokenJsonRenderer bean. See the token rendering documentation for more details.

This authentication filter will only be applied to the above configured URL and can also be disabled, in case a different approach for token creation is followed. In the rest of the cases, the request will continue through the filter chain, reaching Spring Security Core filters. Bear in mind that, by default, Spring Security Core 2.x locks down all URL's unless a explicit securiy rule has been specified for each of them.

See Spring Security Core documentation for more information.

The following are the Config.groovy properties available:

Config keyDefault value
grails.plugin.springsecurity.rest.login.activetrue
grails.plugin.springsecurity.rest.login.endpointUrl/api/login
grails.plugin.springsecurity.rest.login.failureStatusCode401

Extracting credentials from the request

The plugin supports 2 ways of extracting the username and password: using request parameters, and using a JSON payload. To align with the RESTful principles, JSON payload is the default behaviour.

From a JSON request

Config keyDefault value
grails.plugin.springsecurity.rest.login.useJsonCredentialstrue
grails.plugin.springsecurity.rest.login.usernamePropertyNameusername
grails.plugin.springsecurity.rest.login.passwordPropertyNamepassword

The default implementation expects a request like this:

{
    "username": "john.doe",
    "password": "dontTellAnybody"
}

If you use usernamePropertyName and passwordPropertyName properties mentioned above, your JSON request can look like:

{
    "login": "john.doe",
    "pwd": "dontTellAnybody"
}

With the following config:

grails.plugin.springsecurity.rest.login.usernamePropertyName = 'login'
grails.plugin.springsecurity.rest.login.passwordPropertyName = 'pwd'

If your JSON request format is different, you can plug your own implementation by defining a class which extends AbstractJsonPayloadCredentialsExtractor. The default implementation looks like this:

@Slf4j
class DefaultJsonPayloadCredentialsExtractor extends AbstractJsonPayloadCredentialsExtractor {

String usernamePropertyName String passwordPropertyName

UsernamePasswordAuthenticationToken extractCredentials(HttpServletRequest httpServletRequest) { def jsonBody = getJsonBody(httpServletRequest)

String username = jsonBody."${usernamePropertyName}" String password = jsonBody."${passwordPropertyName}"

log.debug "Extracted credentials from JSON payload. Username: ${username}, password: ${password?.size()?'[PROTECTED]':'[MISSING]'}"

new UsernamePasswordAuthenticationToken(username, password) }

}

Once you are done, register it in resources.groovy with the name credentialsExtractor.

From request parameters

Note that the name of the parameters can also be customised:

Config keyDefault value
grails.plugin.springsecurity.rest.login.useRequestParamsCredentialsfalse
grails.plugin.springsecurity.rest.login.usernamePropertyNameusername
grails.plugin.springsecurity.rest.login.passwordPropertyNamepassword

4.1 Logout Endpoint

The logout filter exposes an endpoint for deleting tokens. It will read the token from an HTTP header. If found, will delete it from the storage, sending a 200 response. Otherwise, it will send a 404 response.

You can configure it in Config.groovy using this properties:

Config keyDefault value
grails.plugin.springsecurity.rest.logout.endpointUrl/api/logout
grails.plugin.springsecurity.rest.token.validation.headerNameX-Auth-Token

5 Token Generation

The plugin comes prepackaged with 2 token generation strategies:

The strategy used is configurable in Config.groovy:

Config keyDefault value
grails.plugin.springsecurity.rest.token.generation.useSecureRandomtrue
grails.plugin.springsecurity.rest.token.generation.useUUIDfalse

Both of them generate tokens of 32 alphanumeric characters.

That should be enough for most of the human beings. But if you still want to provide your own implementation, simply write a class implementing TokenGenerator and wire it up in resources.groovy as tokenGenerator.

6 Token Storage

The tokens are stored on the server using a tokenStorageService bean. The plugin comes with out-of-the-box support for Memcached, GORM and Grails Cache, but you can use your own strategy implementing the TokenStorageService interface.

6.1 Memcached

To use Memcached, simply define the following configuration properties to match your environments accordingly:

Config keyDefault value
grails.plugin.springsecurity.rest.token.storage.useMemcachedfalse
grails.plugin.springsecurity.rest.token.storage.memcached.hostslocalhost:11211
grails.plugin.springsecurity.rest.token.storage.memcached.username''
grails.plugin.springsecurity.rest.token.storage.memcached.password''
grails.plugin.springsecurity.rest.token.storage.memcached.expiration3600

For development, if you have Memcached installed locally with the default settings, just define grails.plugin.springsecurity.rest.token.storage.useMemcached = true. It should work.

6.2 GORM

To use GORM, those are the relevant configuration properties:

Config keyDefault value
grails.plugin.springsecurity.rest.token.storage.useGormfalse
grails.plugin.springsecurity.rest.token.storage.gorm.tokenDomainClassNamenull
grails.plugin.springsecurity.rest.token.storage.gorm.tokenValuePropertyNametokenValue
grails.plugin.springsecurity.rest.token.storage.gorm.usernamePropertyNameusername

Please note that for tokenDomainClassName you must enter a fully qualified class name.

The domain class should look like this:

class AuthenticationToken {

String tokenValue String username }

In this case, instead of storing the whole UserDetails object, only the username is stored. This is because applications using this strategy will probably have the standard User and Role domain classes. Then, the username is passed to the default userDetailsService bean, which in the case of the default Spring Security Core GORM implementation will fetch the information from the mentioned domain classes.

6.3 Grails Cache

To use Grails Cache, simply define a cache name:

Config keyDefault value
grails.plugin.springsecurity.rest.token.storage.useGrailsCachefalse
grails.plugin.springsecurity.rest.token.storage.grailsCacheNamenull

The cache name should correspond to a name specified in the cache DSL.

Token expiration / eviction / TTL

By default, Spring Cache abstraction does not support expiration. It depends on the specific support of the actual providers. Grails has several plugins for this:

7 Token Rendering

By default, this plugin renders the token in RFC 6750 Bearer Token format:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{ "access_token":"3bicek1gc63oai6tfjkhog4kqn8ojd6a", "token_type":"Bearer", "username": "john.doe", "roles": [ "ROLE_ADMIN", "ROLE_USER" ] }

As per the RFC, access_token and token_type property names cannot be customised.

The JSON structure can be customised with the following configuration keys:

Config keyDefault value
grails.plugin.springsecurity.rest.token.rendering.usernamePropertyNameusername
grails.plugin.springsecurity.rest.token.rendering.authoritiesPropertyNameroles

Eg, with the following configuration:

grails.plugin.springsecurity.rest.token.rendering.usernamePropertyName = 'login'
grails.plugin.springsecurity.rest.token.rendering.authoritiesPropertyName = 'permissions'

The output will look like:

{
    "access_token":"3bicek1gc63oai6tfjkhog4kqn8ojd6a",
    "token_type":"Bearer",
    "login": "john.doe",
    "permissions": [
        "ROLE_ADMIN",
        "ROLE_USER"
    ]
}

Disabling bearer tokens support for full response customisation

In order to fully customise the response, you need first to disable bearer tokens support by setting grails.plugin.springsecurity.rest.token.validation.useBearerToken = false. That will enable you to use this additional property:

Config keyDefault value
grails.plugin.springsecurity.rest.token.rendering.tokenPropertyNameaccess_token

Disabling bearer token support impacts the way tokens are extracted from the HTTP request. Please, read carefully the chapter about token validation first.

If you want your own implementation, simply create a class implementing RestAuthenticationTokenJsonRenderer and wire it up in resources.groovy with name restAuthenticationTokenJsonRenderer.

The principal object stored in the security context, and passed to the JSON renderer, is coming from the configured authentication providers. In most cases, this will be a UserDetails object retrieved using the userDetailsService bean. If you want to render additional information in your JSON response, you have to:
  1. Configure an alternative userDetailsService bean that retrieves the additional information you want, and put it in a principal object.
  2. Configure an alternative restAuthenticationTokenJsonRenderer that reads that information from the restAuthenticationToken.principal object.

8 Token Validation Filter

The token validation filter looks for the token in the request and then tries to validate it using the configured token storage implementation.

If the validation is successful, the principal object is stored in the security context. This allows you to use in your application @Secured, springSecurityService.principal and so on.

springSecurityService.currentUser expects a grails.plugin.springsecurity.userdetails.GrailsUser to perform a DB query. However, this plugins stores in the security context just a principal Object, because it does not assume you are using domain classes to store the users. Use springSecurityService.principal instead.

This plugin supports RFC 6750 Bearer Token specification out-of-the-box.

Sending tokens in the request

The token can be sent in the Authorization request reader:

GET /protectedResource HTTP/1.1
Host: server.example.com
Authorization: Bearer 3bicek1gc63oai6tfjkhog4kqn8ojd6a

Or using form-encoded body parameters:

POST /protectedResource HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

access_token=3bicek1gc63oai6tfjkhog4kqn8ojd6a

Note that in this case, GET HTTP method is not supported.

If you disable the bearer token support, you can customise it further:

grails.plugin.springsecurity.rest.token.validation.useBearerToken = false
grails.plugin.springsecurity.rest.token.validation.headerName = 'X-Auth-Token'

If you still want to have full access and read the token from a different part of the request, you can implement a TokenReader and register it in your resources.groovy as tokenReader.

Anonymous access

If you want to enable anonymous access to URL's where this plugin's filters are applied, you need to:

  1. Configure enableAnonymousAccess = true (see table below).
  2. Make sure that the anonymousAuthenticationFilter is applied before restTokenValidationFilter. See how to configure filters for more details.

For example, with this configuration:

grails {
    plugin {
        springsecurity {
            filterChain {
                chainMap = [
                    '/api/guest/**': 'anonymousAuthenticationFilter,restTokenValidationFilter,restExceptionTranslationFilter,filterInvocationInterceptor',
                    '/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter',
                    '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
                ]
            }

//Other Spring Security settings //...

rest { token { validation { enableAnonymousAccess = true } } } } } }

The following chains are configured:

  1. /api/guest/** is a stateless chain that allows anonymous access when no token is sent. If however a token is on the request, it will be validated.
  2. /api/** is a stateless chain that doesn't allow anonymous access. Thus, the token will always be required, and if missing, a Bad Request reponse will be sent back to the client.
  3. /** (read: everything else) is a traditional stateful chain.

Validation Endpoint

There is also an endpoint available that you can call in case you want to know if a given token is valid. It looks for the token in a HTTP header as well, and if the token is still valid, it renders its JSON representation. If the token does not exist, it will render a grails.plugin.springsecurity.rest.login.failureStatusCode response (401 by default).

The relevant configuration properties for the validation endpoint are:

Config keyDefault value
grails.plugin.springsecurity.rest.token.validation.activetrue
grails.plugin.springsecurity.rest.token.validation.headerNameX-Auth-Token
grails.plugin.springsecurity.rest.token.validation.endpointUrl/api/validate

9 CORS support

This plugin comes pre-installed with the CORS plugin, which enables Cross-Origin Resource Sharing. Refer to the plugin documentation to learn how to configure it.

The CORS plugin activates itself by default. If you don't want it for some environments, you can use cors.enabled = false within the appropriate environment block in your Config.groovy.

If you don't want CORS support at all, you can skip the plugin by excluding it when defining this plugin in your BuildConfig.groovy:

compile ':spring-security-rest:{{VERSION}}', {
    exclude 'cors
}

10 Delegating authentication to OAuth providers

This plugin is meant to be used in applications serving a REST API's to pure Javascript clients. The main authentication flow of this plugin is to allow you to authenticate your users against any Spring Security-compatible user directory (like a DB or an LDAP server).

However, there might be situations where you want to delegate the authentication against a third-party provider, like Google or Facebook. Unfortunately, your pure Javascript front-end application cannot request the providers directly using OAuth, because then the access keys will be made public.

So is this plugin's responsibility to provide endpoints so your Grails backend acts as a proxy for your front-end client.

The flow is something like the following:

  1. The client application requests and endpoint that requires authentication, so the server responds with a 401 response (*).
  2. The client redirects the user to the login form (*).
  3. This time, instead of using username and password, the user clicks on "Login with Google" button.
  4. Browser navigates to a Grails URL. Grails will generate a Google Login URL, giving Google a Grails callback URL.
  5. Browser navigates to Google Login. User logs in, and Google redirects the browser to the Grails callback URL.
  6. Browser navigates to that Grails callback URL. Then, Grails will use OAuth to fetch user information (like email) from Google. Based on that, will generate a REST API token and fetch and store principal information. The response from Grails will be a front-end URL where the token is a parameter.
  7. The browser will navigate to that URL, and the Javascript logic will read the token from the URL and store it locally.
  8. The client sends again a request to the protected resource, passing the token as an HTTP header (*).

The steps flagged with (*) remain unchanged from the normal flow.

To support OAuth, this plugin uses Profile & Authentication Client for Java. So you can use any OAuth 2.0 provider they support. This includes at the time of writing:

  • Dropbox.
  • Facebook.
  • GitHub.
  • Google.
  • LinkedIn.
  • Twitter.
  • Windows Live.
  • Wordpress.
  • Yahoo.
  • Paypal.

Remember: only OAuth 2.0 providers are supported by this plugin at the moment.

To start the OAuth authentication flow, from your frontend application, generate a link to <YOUR_GRAILS_APP>/oauth/authenticate/<provider>. The user clicking on that link represents step 4 in the previous diagram.

Note that you can define the frontend callback URL in Config.groovy under grails.plugin.springsecurity.rest.oauth.frontendCallbackUrl. You need to define a closure that will be called with the token value as parameter:

grails.plugin.springsecurity.rest.oauth.frontendCallbackUrl = { String tokenValue -> "http://my.frontend-app.com/welcome#token=${tokenValue}" }

You can also define the URL as a callback parameter in the original link, eg:

http://your-grails-api.com/oauth/authenticate/google?callback=http://your-frontend-app.com/auth-success.html?token=

In this case, the token will be concatenated to the end of the URL.

Upon successful OAuth authorisation (after step 6.1 in the above diagram), an OauthUser will be stored in the security context. This is done by a bean named oauthUserDetailsService. The default implementation delegates to the configured userDetailsService bean, passing the profile ID as the username:

/**
 * Builds an {link OauthUser}. Delegates to the default {link UserDetailsService#loadUserByUsername(java.lang.String)}
 * where the username passed is {@link UserProfile#getId()}. If the user is not found, it will create a new one with
 * the the default roles.
 */
@Slf4j
class DefaultOauthUserDetailsService implements OauthUserDetailsService {

@Delegate UserDetailsService userDetailsService

OauthUser loadUserByUserProfile(OAuth20Profile userProfile, Collection<GrantedAuthority> defaultRoles) throws UsernameNotFoundException { UserDetails userDetails OauthUser oauthUser

try { log.debug "Trying to fetch user details for user profile: ${userProfile}" userDetails = userDetailsService.loadUserByUsername userProfile.id Collection<GrantedAuthority> allRoles = userDetails.authorities + defaultRoles oauthUser = new OauthUser(userDetails.username, userDetails.password, allRoles, userProfile) } catch (UsernameNotFoundException unfe) { log.debug "User not found. Creating a new one with default roles: ${defaultRoles}" oauthUser = new OauthUser(userProfile.id, 'N/A', defaultRoles, userProfile) } return oauthUser }

}

If you want to provide your own implementation, define it in resources.groovy with bean name oauthUserDetailsService. Make sure you implements the interface OauthUserDetailsService

If you want to do any additional post-OAuth authorisation check, you should do it on your loadUserByUserProfile implementation. This is useful if you want to allow your corporate users to log into your application using their Gmail account. In this case, you should decide based on OAuth20Profile.getEmail(), for instance:

OauthUser loadUserByUserProfile(OAuth20Profile userProfile, Collection<GrantedAuthority> defaultRoles) throws UsernameNotFoundException {
    if (userProfile.email.endsWith('example.org')) {
        return new OauthUser(userProfile.id, 'N/A', defaultRoles, userProfile)
    } else {
        throw new UsernameNotFoundException("User with email ${userProfile.email} now allowed. Only @example.org accounts are allowed.")
    }
}

In case of any OAuth authentication failure, the plugin will redirect back to the frontend application anyway, so it has a chance to render a proper error message and/or offer the user the option to try again. In that case, the token parameter will be empty, and both error and message params will be appended:

http://your-frontend-app.com/auth-success.html?token=&error=403&message=User+with+email+jimmy%40gmail.com+now+allowed.+Only+%40example.com+accounts+are+allowed

Below are some examples on how to configure it for Google, Facebook and Twitter.

10.1 Google

Define the following block in your Config.groovy:

grails {
    plugin {
        springsecurity {

rest {

oauth {

frontendCallbackUrl = { String tokenValue -> "http://my.frontend-app.com/welcome#token=${tokenValue}" }

google {

client = org.pac4j.oauth.client.Google2Client key = 'xxxx.apps.googleusercontent.com' secret = 'xxx' scope = org.pac4j.oauth.client.Google2Client.Google2Scope.EMAIL_AND_PROFILE defaultRoles = ['ROLE_USER', 'ROLE_GOOGLE']

} } } } } }

The scope can be from any value of the enum org.pac4j.oauth.client.Google2Client.Google2Scope. But if you use the default OauthUserDetailsService, you need to use EMAIL_AND_PROFILE. That is because the default implementation uses the profile ID as the username, and that is only returned by Google if EMAIL_AND_PROFILE scope is used.

10.2 Facebook

Define the following block in your Config.groovy:

grails {
    plugin {
        springsecurity {

rest {

oauth {

frontendCallbackUrl = { String tokenValue -> "http://my.frontend-app.com/welcome#token=${tokenValue}" }

facebook {

client = org.pac4j.oauth.client.FacebookClient key = 'xxx' secret = 'yyy' scope = 'email,user_location' fields = 'id,name,first_name,middle_name,last_name,username' defaultRoles = ['ROLE_USER', 'ROLE_FACEBOOK'] } } } } } }

The scope is a comma-separated list, without blanks, of Facebook permissions. See the Facebook documentation for more details.

fields may contain a comma-separated list, without blanks, of user fields.

Both scope and fields are optional, but it's highly recommendable to fine tune those lists so you don't ask for information you don't need.

10.3 Twitter

Define the following block in your Config.groovy:

grails {
    plugin {
        springsecurity {

rest {

oauth {

frontendCallbackUrl = { String tokenValue -> "http://my.frontend-app.com/welcome#token=${tokenValue}" }

twitter {

client = org.pac4j.oauth.client.TwitterClient key = 'xxx' secret = 'yyy' defaultRoles = ['ROLE_USER', 'ROLE_TWITTER'] } } } } } }

There is no additional configuration for Twitter.

11 Debugging

If you need debug information, you can specify the following entries in Config.groovy:

log4j = {
    ...

debug 'com.odobo', 'grails.app.controllers.com.odobo', 'grails.app.services.com.odobo', 'org.pac4j', 'org.springframework.security'

… }

12 Frequently Asked Questions

Why this token-based implementation? Can't I use HTTP basic authentication?

In theory you can. The only restriction to be truly stateless is to not use HTTP sessions at all. So if you go with basic authentication, you need to transfer the credentials back and forth every time.

Let's think about that. Keep in mind that your frontend is a pure HTML/Javascript application, consuming a REST API from the Grails side. So the first time, the Javascript application will make an API query and will receive a 401 response indicating that authentication is required. Then you present the user a form to enter credentials, you grab them, encode them with Base64 and in the next request, you send an HTTP header like Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==.

Now remember you are doing RESTful application, so the session state is maintained in the client. That means that you would need to store that Base64 encoded string somewhere: cookies? HTML5 local storage? In any case, they are accessible using browser tools. And that's the point: there is a huge security risk because Base64 it's not encryption, just encoding. And it can be easily decoded.

You could argue that someone can access the token in the browser. Yes, but having the token will not allow him to obtain user's credentials. The tokens are just not decodable. And they can be revoked if necessary.

Fortunately for you, a token-based solution is not a magic idea that I only got; it's actually a specification: RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage.

There is also more reasons to be in favour of tokens:

  • With basic auth, every single API call would have to check credentials. In the token-based implementation, specially if you use Memcached, the authentication results are cached.
  • With basic auth, you are sending the credentials all the time. Ok, you can use SSL, but still I think it's more elegant to use tokens.

Moreover, if you use tokens, you have the chance to implement expiration policies.

A couple of link with further explanations on the token-based flow:

Why can't the API be secured with OAuth?

RFC 6749 - OAuth 2.0 specification does cover this scenario in what they call "public clients":

Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web browser-based application), and incapable of secure client
authentication via any other means.

Using OAuth, you would need to store consumer key and consumer secret in the browser. Seriously, you don't want to do that. The problem with OAuth is that it's designed for when the consumer is a server-side application. And it just does not work well with pure Javascript front-ends. In this scenario, your frontend would be the OAuth consumer and your Grails backend the OAuth provider.

The OAuth 2.0 specification supports public clients with the implicit grant. This plugin supports that by default when you delegate the authentication to another OAuth provider. If it's you who are authenticating the users (via DB, LDAP, etc), the token-based flow of this plugin is OAuth-ish .

Why you didn't use any of the existing OAuth plugins? Why pac4j?

I'm aware of plugins like OAuth and Spring Security OAuth, but all of them rely on Spring Security Core's way of using HTTP sessions. So not acceptable.

I chose pac4j because:

  1. They support major OAuth 2.0 providers out-of-the-box, whereas Scribe does not.
  2. It's deadly simple and works just fine.

I'm also aware of a pac4j-spring-security module. See my previous response on HTTP sessions.

Dude, this is awesome. How can I compensate you?

I doubt you can :). You may try giving me free beers the next time you see me in a conference. Or you can just express your gratitude via Twitter.