Monday, October 30, 2017

Using OAuth 2.0 Refresh Tokens in WSO2 Identity Server

In my previous blog post [1], I provided basic steps for getting started with OAuth [2] using WSO2 Identity Server. In this post, I’m explaining how to use OAuth refresh tokens for renewing the access tokens issued by the Identity Server.

For getting started, follow my previous blog post and get the Service Provider configuration registered with the OAuth application for obtaining the client ID and client secret values. Make sure in the OAuth configuration, you select the checkbox ‘Refresh Token.


According to OAuth 2.0 specification, the “Authorization Code” grant type and “Resource Owner Password Credentials” grant type should optionally provide a refresh token in the OAuth access token response.

Following my previous blog post, try out either the Authorization Code or Resource Owner Password Credentials grant type and obtain the OAuth access token response. You should receive a JSON response as following.


{
  "access_token":"346c4ad5-3834-3871-aaee-7c941518a73a",
  "refresh_token":"4802a683-d227-3be8-85f1-53b5fa91668a",
  "scope":"openid",
  "id_token":"eyJ4NXQiOiJObUptT0dVeE16WmxZak0yWkRSaE5UWmxZVEExWXpkaFpUUmlPV0UwTldJMk0ySm1PVGMxWkEiLCJraWQiOiJkMGVjNTE0YTMyYjZmODhjMGFiZDEyYTI4NDA2OTliZGQzZGViYTlkIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiLWJtODR6bWlyQlEtUnpLSkUtVGtZZyIsImFjciI6InVybjptYWNlOmluY29tbW9uOmlhcDpzaWx2ZXIiLCJzdWIiOiJhZG1pbkBjYXJib24uc3VwZXIiLCJhdWQiOlsiWFpzQkVsN1JBaVZXbUpvVTZOWENGQ3ltWUZJYSJdLCJhenAiOiJYWnNCRWw3UkFpVldtSm9VNk5YQ0ZDeW1ZRklhIiwiaXNzIjoiaHR0cHM6XC9cL2xvY2FsaG9zdDo5NDQzXC9vYXV0aDJcL3Rva2VuIiwiZXhwIjoxNTA5MzcxNTU3LCJpYXQiOjE1MDkzNjc5NTd9.WRmgUp3bxawa_L_SAAuV43CV9quJkBLXyr2b3lwx3AV4T6hbRVoWbnzGkwf8L8pTe0vv76bejDSOeqnPmh6IsW7alCTC58chlTzDEGspj65sYi4mxKw0xO95qdPa1MAD_mHtsibxLaRSqPHSa3rIWaoS4ur94fUccKE3vZ8A5fw",
  "token_type":"Bearer",
  "expires_in":3600
}

Now that we have the access token, we can invoke the User Information Endpoint and get the default user claims as following.

Request
curl -k -X POST -H "Authorization: Bearer <access_token_value>" https://localhost:9443/oauth2/userinfo?schema=openid

Response
{"sub":"admin"}

Once the access token is expired, if you try out the same above request, you would get the following

{
  "error_description":"Access token validation failed",
  "error":"invalid_token"
}

However, for trying out renewing the access token, we don’t need to wait until the token is expired. You can make the following request to the token endpoint of Identity Server. (Here, the Authorization header value given as XXX is the base64 encoded value of client_id:client_secret). For the refresh_token parameter, we need to provide the value received in the token response we received previously. Here I am not sending the scope parameter because I am requesting the new access token with the same scopes it was issued previously. However, if we need to obtain the new access token with a subset of scopes which the previous token was authorized for, then we need to include the scope as a parameter with the required scopes.

curl -k -X POST -H "Authorization: Basic XXX" -H “Content-Type: application/x-www-form-urlencoded” --data "grant_type=refresh_token&refresh_token=XXXX" https://localhost:9443/oauth2/token


As the response to the above request, we would receive the same OAuth 2.0 access token response which includes a new access token and a new refresh token.

When you renew an access token, Identity Server will automatically set the previously issued access token to be inactive (not usable) regardless of its expiry. This happens only if the token scope is same for the new token as well. If the token scope is different (a subset), then Identity Server will not mark the previous token as inactive, instead of that it will issue a new token where both the old and new tokens would be valid until their expiry.  

These OAuth access tokens are stored in the IDN_OAUTH2_ACCESS_TOKEN table in the database.


The validity periods of the OAuth access tokens and refresh tokens are defined in the IS_HOME/repository/conf/identity/identity.xml file. Following are the properties which are useful for you.

<!-- Default validity period for application access tokens in seconds -->
<AccessTokenDefaultValidityPeriod>3600</AccessTokenDefaultValidityPeriod>

<!-- Default validity period for user access tokens in seconds -->
<UserAccessTokenDefaultValidityPeriod>3600</UserAccessTokenDefaultValidityPeriod>

<!-- Validity period for refresh token -->
<RefreshTokenValidityPeriod>84600</RefreshTokenValidityPeriod>

   
References



Tharindu Edirisinghe
Platform Security Team
WSO2

Wednesday, October 11, 2017

Getting Started with OAuth 2.0 using WSO2 Identity Server

WSO2 Identity Server can act as an authorization server in OAuth 2.0 [1] protocol. In this blog post, I am providing the steps for you to try out each OAuth grant type using WSO2 Identity Server. As the Identity Server supports the standard requests and responses in OAuth grant types, the same steps would be applicable for other OAuth authorization servers as well. Here I use the Identity Server 5.3.0 version, which is the latest released GA version at the time of this writing.

Protocol Endpoints

Once you start WSO2 Identity Server, by default it runs on localhost and on port 9443. So, the OAuth 2.0 protocol endpoints in the authorization server are as following.

Authorization Endpoint : https://localhost:9443/oauth2/authorize


Client Registration

Before making OAuth requests, we should register a client application in Identity Server to obtain the credentials of the client.

Login to the Management Console and Add a Service Provider.


In the Service Provider configuration, expand Inbound Authentication Configuration and under that you will find OAuth/OpenID Connect Configuration. Click on the Configure option there.


The Callback URL is the Redirection Endpoint (redirect_uri) of the client application where the authorization server should send the responses. Here I define the redirect_uri with the dummy value http://myoauthclient.com/callback although I do not have a client application running in that URL. That is fine because we can manually run through all the OAuth grant types using any dummy redirect_uri. If you are trying this out, you can put any URL as you wish.

In the configuration, it has checkboxes for each grant type. I am keeping all the checkboxes selected here, although in this article I will only demonstrate the authorization code, implicit, resource owner password credentials and client credentials grant types.

After successfully registering the OAuth client application, we can obtain the Client Key and Client Secret for the application. Update the service provider to persist the configuration of the OAuth client.

These are the values I have got. When you try out the same steps, you can use the values which you have received.

Client Key : 3T6XUzSJBZVHWlyzfV0Q3d7r7DEa
Client Secret : 39jR0RugVmUIfnVLgWVnfkEHIUoa


Authorization Code Grant Type

For trying out the authorization code grant type, we can prepare a URL like below (to the authorization endpoint of Identity Server with required query parameters) and visit that in the browser. Note that the redirect_uri is URL encoded.


Then, Identity Server would authenticate the user (resource owner). Here I need to provide user account credentials and login to Identity Server.


Then it will show the User Consent Page and ask the user to grant authorization for the client for the requested scopes.


Then, Identity Server will redirect the user agent (browser) to the redirect_uri with the query parameter ‘code’ that has the authorization code value. (Here since I don’t have a web application running in the redirect_uri, it shows the error. However I can manually extract the authorization code from the URL and continue the flow.

Now that we have the authorization code, next step is to request the OAuth access token from the Token Endpoint of the Identity Server. Here, we need to authenticate the client application. For that, in the HTTP Headers, I need to use the “Authorization: Basic XXX” header where the value is the Base 64 encoded string of ClientID:ClientSecret value.

I am using curl for making the HTTP POST request to the Token Endpoint. Similarly we can use any HTTP client (even RESTClient addon in browser).


curl -k -X POST --header "Authorization: Basic M1Q2WFV6U0pCWlZIV2x5emZWMFEzZDdyN0RFYTozOWpSMFJ1Z1ZtVUlmblZMZ1dWbmZrRUhJVW9h" --data "grant_type=authorization_code&redirect_uri=http%3A%2F%2Fmyoauthclient.com%2Fcallback&code=3d7f3e3c-8989-3301-8fdc-4f912fd2d5f8" https://localhost:9443/oauth2/token



As the response, I receive the following JSON payload which contains the OAuth access token and also the refresh token.


{
  "access_token":"44b279b3-2c3b-3a6f-b51b-845c15f3dd26",
  "refresh_token":"9380f382-dfd7-39d2-bee6-a89162d19d37",
  "scope":"openid",
  "id_token":"eyJ4NXQiOiJObUptT0dVeE16WmxZak0yWkRSaE5UWmxZVEExWXpkaFpUUmlPV0UwTldJMk0ySm1PVGMxWkEiLCJraWQiOiJkMGVjNTE0YTMyYjZmODhjMGFiZDEyYTI4NDA2OTliZGQzZGViYTlkIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoidWlob20wZXNhelZJMHI3WUtJLUJuUSIsInN1YiI6ImFkbWluIiwiYXVkIjpbIjNUNlhVelNKQlpWSFdseXpmVjBRM2Q3cjdERWEiXSwiYXpwIjoiM1Q2WFV6U0pCWlZIV2x5emZWMFEzZDdyN0RFYSIsImF1dGhfdGltZSI6MTUwNzc1MjQwMCwiaXNzIjoiaHR0cHM6XC9cL2xvY2FsaG9zdDo5NDQzXC9vYXV0aDJcL3Rva2VuIiwiZXhwIjoxNTA3NzU2MTc3LCJpYXQiOjE1MDc3NTI1Nzd9.hM43uJBQyI72OJXzHKzB0C1AxBgaOSPi6PySJr7HJyeR1k-AXxCDuWGfTsSVSf4WZNfaPaxMgw-xyjmLVztyqXOpXQXolDgnOMwkJYc4vrDrkg7gqxJhpoedS_bdg1905Gj-xYBawNfxYSdEXoaYxNIoGpTYOBSlK2wtxm0ExbE",
  "token_type":"Bearer",
  "expires_in":3600
}


Implicit Grant Type

In this grant, we can prepare the URL as following with the required parameters and invoke the authorization endpoint of Identity Server.


Once we access this URL in the browser, it will prompt for user authentication (if the user is not already logged into Identity Server) and then it will get the user’s approval from the User Consent page. Finally it will redirect the user-agent to the redirect_uri where the OAuth access token would be sent in the URL fragment.



Resource Owner Password Credentials Grant Type

Here we directly invoke the Token Endpoint of Identity Server with the required parameters. In the HTTP body, we need to provide the resource owner’s credentials as username and password parameters. In the HTTP Authorization header, we need to send the client’s credentials (clientID and clientSecret).

curl -k -X POST -H "Authorization: Basic M1Q2WFV6U0pCWlZIV2x5emZWMFEzZDdyN0RFYTozOWpSMFJ1Z1ZtVUlmblZMZ1dWbmZrRUhJVW9h" --data "grant_type=password&scope=openid&username=admin&password=admin" https://localhost:9443/oauth2/token

The response we get here is similar to Authorization Code grant’s response.



Client Credentials Grant Type

Here, we directly invoke the Token Endpoint of Identity Server, sending the required parameters. For authenticating the client, we use the Authorization HTTP header.

curl -k -X POST -H "Authorization: Basic M1Q2WFV6U0pCWlZIV2x5emZWMFEzZDdyN0RFYTozOWpSMFJ1Z1ZtVUlmblZMZ1dWbmZrRUhJVW9h" --data "grant_type=client_credentials&scope=openid" https://localhost:9443/oauth2/token


Retrieving User Profile Information using OAuth Access Token

Once we have obtained the OAuth access token for a user, then we can invoke the User Info Endpoint of Identity Server providing the access token in the Authorization header as a bearer token.

curl -k -X POST -H "Authorization: Bearer 44b279b3-2c3b-3a6f-b51b-845c15f3dd26" https://localhost:9443/oauth2/userinfo?schema=openid

Then in the response, we receive the user’s profile attributes as a JSON message.


We can configure the attributes to be received in the JSON response from the Service Provider configuration. In the Claim Configuration section of the Service Provider, we can add the claims we require in the response.


Additionally, we need to make sure the request claim URIs are already there in the OIDC claim dialect (http://wso2.org/oidc/claim). If a claim is not already there in the OIDC claim dialect, then we need to add it in order to be included in the JSON response sent by the Identity Server.

Also, we need to make sure the user’s profile has the values set for the claims that we need to include in the response.



References


Tharindu Edirisinghe
Platform Security Team
WSO2