My interest in using Bearer Authentication Tokens in Microservices began after reading this 2012 Shiro User Forum Post by Les Hazlewood. Then I saw a new Bootique User Group Forum question on REST Authentication and was motivated to design and implement a Bearer Authentication Token strategy in a Bootique Microservices application. The working source can be found in my NixMash Bootique Microservices Demo application on GitHub. We're going to cover a lot of code in this post but you can grab the source and peruse it at your leisure.
The Bearer Token Concept is described by Les Hazlewood in his 2012 Shiro Forum reply. For our uses, it is where a Shiro User, the Bearer, passes a token to a Microservice REST Endpoint. The client, in our case a Web Client, has its own Shiro Authorizing Realm. The Microservice, on the other hand, has a completely separate Shiro Authorizing Realm based on the Bearer Authentication Token passed from one or multiple clients. As a crude simplification, think of Bearer Authentication Tokens as a fancy way of authenticating users based on a USERKEY as opposed to a USERNAME and PASSWORD.
Our Shiro Bearer Authentication Token must extend Shiro AuthenticationToken. Our BearerAuthenticationToken object has properties token, username and password, though all of the action happens in token as you will see.
This is the creation of a BearerAuthenticationToken object in our Web Client that we will be passing to our REST Microservice. We are encoding the CurrentUser userKey, a serviceApiKey representing our Web Client, and the appId Application Designation which we will use to validate the key on the other side.
The BearerAuthenticationToken token key when encoded will look like this, which is what we transmit to the Microservice.
We're getting a bit ahead of ourselves, but this is what the token key will look like when decoded where you see the individual properties of userkey, apikey and appId.
Now we can send the encrypted token key to our REST Microservice as a simple Path Parameter. We can send it anyway we want, of course.
Our REST Microservice Endpoint receives the token key and authenticates the Shiro User in its BearerTokenRealm. Notice that a Shiro Subject is created and logs in to our BearerTokenRealm with the token, exactly as in our Web Client where we perform a login with a UserPasswordToken object.
Our BearerTokenRealm extends Shiro AuthorizingRealm, just like our Username/Password Realm in the Web Client. We first decode our BearerAuthenticationToken (1) and validate the token on the Application ID and Api Key (2). We now can authorize the user based on the UserKey (3) and obtain that user's roles and permissions along the way.
Our token check is found at the bottom of the Demo App Home Page. All we're doing is determining if the user has the Role of admin. If so they can "perform this task."
User BOB logs in. Bob is an admin. Rock on, Bob!
To use BearerAuthorizationToken you'll need a few support methods, like the ability to create Anonymous Tokens, for example.
Here are a couple of tips when using Bootique, both of which pertain to the REST Microservice. First, you will add your BearerTokenRealm in the Microservice as any Bootique Shiro Realm.
You will need a Shiro Security Manager available to perform security operations and manage state in your application. Bootique handles that for you, where all you have to do is @Inject the Shiro SecurityManager in your Resource Class.
Source code discussed in this post is found in my NixMash Bootique Microservices Demo app on GitHub.