TFIM OAuth Mobile Demonstration – Under the hood
In my previous article I presented a demonstration of a mobile application retrieving a protected resource (a set of user profile attributes) from a website using OAuth 2.0. In this article I’ll explain the rationale for using OAuth 2.0, show you the exact message transactions used by that application and present some of the variables you need to consider when making design/deployment decisions for such an environment. An understanding of the OAuth 2.0 Protocol and the Bearer Token Specification is an advantage when reading this article.
Why use OAuth 2.0
I believe the number one reason for using OAuth 2.0 as opposed to alternative security protocols is its relative ease of use for client application developers. By lowering the technical entry point for client developers you have the opportunity to reach more customers. Sure, developers can still get it wrong by not following security best practices such as requiring secure transport with server certificate validation, storing keys insecurely, etc, but these flaws are possible with other protocols as well. Given that those baseline best practices are followed, writing OAuth 2.0 clients is really trivial.
OAuth 2.0 is also an emerging standard with widespread adoption and this means that client application developers will be increasingly seeing the same deployment patterns time and again allowing for code re-use, client library development which does incorporate security best practices, etc. Being a standard is a good thing.
Messages used for the Mobile Demonstration Application
In this section I will show you exactly how the mobile application communicates with the TFIM demonstration site. You can “be a mobile phone app” with just a few simple curl commands.
For the technically minded comfortable with OAuth 2.0, here’s the key information you’d need to develop the mobile application:
Let’s get started!
Obtaining an authorization code
This step requires the resource owner to use a browser at the service provider. Here’s the URL: https://tfim01.demos.ibm.com/FIM/sps/oauth20sp/oauth20/authorize?client_id=mobileClient&response_type=code
Remember scope is optional and you can explicitly added something like scope=attr1 attr2 to the parameter list. Following authentication and authorization, the resource owner will see the authorization code on the screen of the service provider, and manually provides it to the client.
This screenshot shows the authorize step where the user decides which attributes to grant access to, and assigns a friendly name for the application instance:
This screenshot shows the authorization code displayed with a reminder that it expires in 60 seconds:
Exchanging an authorization code for an access token and refresh token
The client obtains the authorization code from the resource owner, and exchanges it for an access token and refresh token. The appInstance (friendly name chosen by the user for the application instance) is also returned in the response from the token endpoint. This exchange must be completed within 60 seconds of the authorization code being displayed to the resource owner:
curl -d "client_id=mobileClient&grant_type=authorization_code&code=cioyus"
https://tfim01.demos.ibm.com/FIM/sps/oauth20sp/oauth20/token
{"expires_in":3599,"scope":"email phone","appInstance":"myphone","access_token":"aHWynpQiUYsJ4C4jLJpg",
"token_type":"bearer","refresh_token":"WtFQMWtU88cRdxNoCYl8FJwU7wiAnLbrY0peYSWa"}
If the exchange is not completed within 60 seconds the authorization code expires and the resource owner simply has to get a new one following the same procedure.
Using the access token to request the protected resource
The protected resource can be retrieved with an access token three different ways. All result in the same response:
Using the access token in an Authorization header
curl -H "Authorization: Bearer aHWynpQiUYsJ4C4jLJpg" https://tfim01.demos.ibm.com/FIM/demo/oauthprotected/profile.jsp
Using the access token as a POST body parameter
curl -d "access_token=aHWynpQiUYsJ4C4jLJpg" https://tfim01.demos.ibm.com/FIM/demo/oauthprotected/profile.jsp
Using the access token in a query string
curl https://tfim01.demos.ibm.com/FIM/demo/oauthprotected/profile.jsp?access_token=aHWynpQiUYsJ4C4jLJpg
In each case the response for the protected resource should be the same:
{"timestamp":1324601764437,"username":"sweeden@au1.ibm.com",
"email":["sweeden@au1.ibm.com"],"phone":["55512345","55554321"]}
Using a refresh token to get a new access token and refresh token
When the access token expires, or the application instance has been disabled and then re-enabled at the service provider management interface by the resource owner, the client will get an error when trying to use the access token to get a protected resource. Instead of a 200 OK response with JSON data, a 401 response will be returned, as shown:
curl -v -H "Authorization: Bearer aHWynpQiUYsJ4C4jLJpg" https://tfim01.demos.ibm.com/FIM/demo/oauthprotected/profile.jsp
> GET /FIM/demo/oauthprotected/profile.jsp HTTP/1.1
> User-Agent: curl/7.22.0 (i686-pc-cygwin) libcurl/7.22.0 OpenSSL/0.9.8r zlib/1.2.5 libidn/1.22 libssh2/1.2.7
> Host: tfim01.demos.ibm.com
> Accept: */*
> Authorization: Bearer aHWynpQiUYsJ4C4jLJpg
>
< HTTP/1.1 401
< content-type: text/html
< p3p: CP="NON CUR OTPi OUR NOR UNI"
< www-authenticate: Bearer realm="https://tfim01.demos.ibm.com"
< x-old-content-length: 17
< transfer-encoding: chunked
<
<html>401</html>
The client must then use the refresh token to obtain a new access token:
curl -d "client_id=mobileClient&grant_type=refresh_token&refresh_token=WtFQMWtU88cRdxNoCYl8FJwU7wiAnLbrY0peYSWa"
https://tfim01.demos.ibm.com/FIM/sps/oauth20sp/oauth20/token
{"expires_in":3599,"scope":"email phone","access_token":"GrYWuLN2o3H1QNEfuoVk",
"token_type":"bearer","refresh_token":"GKibcdQrQ9piPxtOzh1iM1KnFfVwu7B5BLHd5AHZ"}
If the client receives an error from the refresh token request that is not a communications error, a severe warning should be displayed to the user as one of the following has happened:
- The resource owner has disabled or deleted the application instance at the service provider.
- The refresh token has been compromised and used by an attacker.
The resource owner should told to login to the service provider at the Manage Mobile Applications page and if the application instance is shown as enabled it should be immediately deleted to revoke access to the attacker who has compromised the refresh token. Re-registration of the application is then possible by beginning with a new authorization code.
Deployment Considerations
When designing this demonstration scenario there were a lot of variables for deployment that were taken into consideration. These include:
- Entropy, lifetime and delivery mechanism of the authorization code. Ultimately we chose manual delivery for simplicity. Therefore we wanted the length to be reasonably short, and chose 6 lower case characters for easy entry into a mobile phone keyboard. As the authorization code is short, a short lifetime was used to reduce attack exposure windows since no client secret is needed to present it to the token endpoint.
- Lifetime and entropy of access tokens. These can be anything you like, we chose an hour for lifetime and 20 alphanumerics for an access token.
- Lifetime and entropy of refresh tokens. In our scenario we made the lifetime of a refresh token infinite, and the length of a refresh token 40 alphanumerics. Again this comes down to personal choice. Longer refresh tokens are simply a configuration choice. The reason we chose to make refresh tokens of infinite lifetime is that when the refresh token expires, re-registration of the application instance is the only option. This may be ok depending on your own use case requirements.
- Concurrency of tokens. In our scenario only one access token and refresh token may be valid at a time per authorization grant. This is quite suitable since the access token and refresh token represent a single instance of the application stored on a phone.
The mobile application scenario is implemented on the server side using Tivoli Federated Identity Manager with a modified version of the OAuth JDBC plugins that I have previously made available, along with a custom Java mapping rule for the OAuth federation that communicates with the database tables used for token storage. Tivoli Access Manager WebSEAL is used as the point of contact, and the WebSEAL enforcement point for OAuth is used for access token validation.
I hope this article helps to explain the value OAuth offers to companies wishing to expose resources and API’s for client applications to call on behalf of your users. Should you have any questions about this scenario or your own business scenario and are considering Tivoli Federated Identity Manager, please contact me.