Configuring and Managing OAuth 2.0

Overview

Client applications that send OAuth requests to the API Gateway’s Authorization Server must be registered with the Authorization Server. This topic describes the OAuth 2.0 endpoints used to manage client applications and the pre-registered examples provided with the API Gateway. It describes the registry used to store these client applications, and provides details how to manage them using a REST API-based HTML interface. This topic also includes details on the database schema, and SSL commands used for the example client applications.

Enabling OAuth 2.0 Management

The API Gateway provides the following endpoints used to manage OAuth 2.0 client applications:

Description

URL

Authorization Endpoint (REST API)

https://GATEWAY:8089/api/oauth/authorize

Token Endpoint (REST API)

https://GATEWAY:8089/api/oauth/token

Token Info Endpoint (REST API)

https://GATEWAY:8089/api/oauth/tokeninfo

Revoke Endpoint (REST API)

https://GATEWAY:8089/api/oauth/revoke

Oracle API Manager (HTML Interface)

https://GATEWAY:8089

Oracle API Manager (REST API)

https://GATEWAY:8089/api/kps/

ClientApplicationRegistry


where GATEWAY is the machine on which the API Gateway is installed.

[Important] Important

You must first enable the OAuth listener port in the API Gateway before these endpoints are available.

Enabling OAuth Endpoints

To enable the OAuth management endpoints on your API Gateway, perform the following steps:

  1. In the Policy Studio tree, select Listeners -> API Gateway -> OAuth 2.0 Services  -> Ports.

  2. Right-click the OAuth 2.0 Interface in the panel on the right, and select Edit.

  3. Select Enable Interface in the dialog.

  4. Click the Deploy button in the toolbar.

  5. Enter a description and click Finish.

[Note] Note

On Linux-based systems, such as Oracle Enterprise Linux, you must open the firewall to allow external access to port 8089.

If you need to change the port number, set the value of the env.PORT.OAUTH2.SERVICES environment variable. For more details, see Deploying the API Gateway in Multiple Environments.

Pre-registered Client Applications

The API Gateway ships with a number of pre-registered example client applications.

[Note] Note

These client applications are for demonstration purposes only and should be removed before moving the Authorization Server into production.

The default example client applications include the following:

Client ID

Client Secret

SampleConfidentialApp

6808d4b6-ef09-4b0d-8f28-3b05da9c48ec

SamplePublicApp

3b001542-e348-443b-9ca2-2f38bd3f3e84


Managing Registered Clients

Every client application that sends OAuth requests to the API Gateway's OAuth Authorization Server must be registered with the Oracle API Manager. The API Gateway provides the API Manager Web-based HTML interface for managing registered client applications. It also provides the API Manager REST API that enables you to manage registered clients on the command line.

Accessing the API Manager Web Interface

You can access the API Manager Web interface at the following URL:

https://localhost:8089

This interface is displayed as follows:

REST API HTML Interface

You can select a registration entry and click Edit to update its details. For example, you can can select the scopes that an application requires access to, and configure API keys or certificates. Remember to click Save when finished.

REST API HTML Interface

By default, the API Manager back-end is file-based and uses the API Gateway’s Key Property Store (KPS). For more details, see Key Property Stores. You can also store this data in a database. For more details, see the section called “Token Management”.

Accessing the API Manager REST API

For details on using the API Manager REST interface on the command line, see the section called “API Manager REST API”.

Sample Clients

The API Gateway includes sample Jython client applications for all supported OAuth flows in the following directory your API Gateway installation:

INSTALL_DIR/samples/scripts/oauth

To run a sample script, open a UNIX shell or DOS command prompt in the following directory:

INSTALL_DIR/samples/scripts

Windows

For example, run the following command:

> run.bat oauth\implicit_grant.py

Linux/Solaris

For example, run the following command:

> sh run.sh oauth/implicit_grant.py

Token Management

The API Gateway can store generated authorization codes and access tokens in its caches or in a central database. The Authorization Server issues tokens to clients on behalf of a Resource Owner for use in authenticating subsequent API calls to the Resource Server. These issued tokens need to be persisted so that subsequent client requests to the Authorization Server can be validated.

The following screen shows the OAuth stores in the Policy Studio:

REST API HTML Interface

[Note] Note

The Authorization Server can cache authorization codes and access tokens depending on the OAuth flow. The steps for adding an authorization code cache are similar to adding an access token cache.

The Authorization Server offers the following token persistent storage options:

  • Database

  • Cache

The following screen shows these options in the Policy Studio:

Add OAuth Token Store

The Purge expired tokens every 60 secs setting enables you to configure the time in seconds that a background process will polls the database or cache looking for expired access/refresh tokens or authorization codes.

Caching Tokens using a Database

Perform the following steps:

  1. Right-click Access Token Stores in the Policy Studio tree, and select Add Access Token Store.

  2. This displays the dialog that enables you to choose the persistence type. Select Store in a database, and select the browse button to display a database configuration dialog.

  3. Complete the database configuration details. The following example uses a MySQL database, and a database instance named oauth_db. For more details, see Database Connection.

Database Connection

[Note] Note

On first use of the database for caching access tokens, the following tables are created automatically: oauth_access_token and oauth_refresh_token. A table named oauth_authz_code is created for caching authorization codes.

For more details, see the section called “Database-Backed API Manager”.

Caching Tokens using EHCache

  1. Right-click Access Token Stores in the Policy Studio tree, and select Add Access Token Store.

  2. This displays a dialog that enables you to choose the persistence type. Select Store in a cache, and select the browse button to display the cache configuration dialog.

  3. Add a new cache (for example, AccessTokenCache). For more details, see Global Caches.

Select Cache

API Manager REST API

This section desribes a set of commands that enables you to use the API Manager REST API to manage client applications.

Register a Client Application

You can register client applications using a command line utility such as curl. For example, to register a new client application, use the following command:

curl -v --header "Content-Type:application/json" -X POST -d @newobj.json 
  --user admin:changeme

where newobj.json is something like the following:

{
      "storeId": "ClientApplicationRegistry",
      "typeId": "AppDetails",
      "objects": [
          {
             "enabled": true,
             "logo": "http://localhost:8090/logos/logo.gif",
             "scopes": [
                 "https://localhost:8090/auth/userinfo.email",
                 "https://localhost:8090/auth/userinfo.profile"
               ],
             "contactPhone": "012345678",
             "contactEmail": "sample@sampleapp.com",
             "description": "Oracle Sample Confidential Application",
             "name": "Oracle Sample Confidential App",
             "clientID": "SampleConfidentialApp",
             "clientSecret": "NjgwOGQ0YjYtZWYwOS00YjBkLThmMjgtM2IwNWRhOWM0OGVj",
             "redirectURLs": [
                 "http://localhost:8080/auth/redirect.html"
               ],
             "base64EncodedCert": 
		     "-----BEGIN CERTIFICATE-----
	         MIIDpTCCAw6gAwIBAgIJAKqGffYjCdSiMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD 
			 .....
			 -----END CERTIFICATE-----\n",
             "clientType": "confidential"
           }
       ]
   }

Retrieve all Registered Clients

Use the following command:

curl --user admin:changeme   | python -mjson.tool

 

Viewing a Registered Client

This is similar to retrieving all registered clients except you are passing in a registered client_id (in this example, 95574d66-f115-4c9b-b93e-526d383b4b6a). Use the following command:

curl --user admin:changeme  
  https://localhost:8089/api/kps/ClientApplicationRegistry/
  95574d66-f115-4c9b-b93e-526d383b4b6a | python -mjson.tool

To access one of the preregistered clients, you can call the following:

curl --user admin:changeme  
  https://localhost:8089/api/kps/ClientApplicationRegistry/
  SampleConfidentialApp | python -mjson.tool

Removing a Registered Client

To delete a client, pass in the client ID at the end of the request. For example:

curl -v -X DELETE --user admin:changeme 
  https://localhost:8089/api/kps/ClientApplicationRegistry/
  95574d66-f115-4c9b-b93e-526d383b4b6a

Verify Client Deletion is Successful

This is the same request as viewing a register client application, but this time the API Manager KPS returns a JSON error. For exmaple:

curl --user admin:changeme  
  https://localhost:8089/api/kps/ClientApplicationRegistry/
  95574d66-f115-4c9b-b93e-526d383b4b6a | python -mjson.tool

The following JSON error is returned:

{
    "errors": [
        {
            "code": 102,
            "message": "Unexpected exception: 
              com.vordel.kps.ObjectNotFound : id: 
              95574d66-f115-4c9b-b93e-526d383b4b6a"
         }
    ]
}

Disabling a Client Application

curl -v --header "Content-Type:application/json" -X PUT -d '{"enabled" : false}'  
  --user admin:changeme https://localhost:8089/api/kps/ClientApplicationRegistry/
    c5659b84-8524-4592-aed8-c7fa77c8eb26

Alternatively, you can upload a full update by passing in a file using -d @updatedObject.json.

Database-Backed API Manager

The Oracle API Manager KPS can also be backed by a database. For more details, see Key Property Stores. The default file-based KPS that ships in the samples directory of the API Gateway is displayed as follows in the Policy Studio:

OAuth File KPS

To change this definition to use a database for storage, add the following property name:value pairs:

  • Database username: username: root

  • Database password: password: password

  • Database URL: url: jdbc:mysql://localhost:3306/oauth_db

  • Database driver: driver: com.mysql.jdbc.Driver

[Note] Note

Alternatively, you can set the dbConnectionName property. This enables you to use a database connection that you have already defined in External Connections -> Database Connections in the Policy Studio. A setting of dbConnectionName means that the usernamepassword, url, and driver properties are not required. The schemaOption parameter, if set to create, creates the database tables required by the KPS. This variable is typically used at development and test time.

For details on adding KPS properties in the Policy Studio, see Key Property Stores.

OAuth Database Schemas

This section shows the OAuth database schemas displayed by example mysql commands.

oauth_access_token schema

The following shows the result from the show columns from auth_access_token; command:

    +---------------+--------------+------+-----+---------+-------+
    | Field         | Type         | Null | Key | Default | Extra |
    +---------------+--------------+------+-----+---------+-------+
    | id            | varchar(2    | NO   | PRI | NULL    |       |
    | auth_request  | blob         | NO   |     | NULL    |       |
    | client_id     | varchar(255  | NO   |     | NULL    |       |
    | expiry_ti     | datetime     | NO   |     | NULL    |       |
    | token         | blob         | NO   |     | NULL    |       |
    | refresh_token | varchar(2    | YES  |     | NULL    |       |
    | user_auth     | varchar(255  | NO   |     | NULL    |       |
    | user_name     | varchar(255  | NO   |     | NULL    |       |
    +---------------+--------------+------+-----+---------+-------+

oauth_refresh_token schema

The following shows the result from the show columns from oauth_refresh_token; command:

    +--------------+--------------+------+-----+---------+-------+
    | Field        | Type         | Null | Key | Default | Extra |
    +--------------+--------------+------+-----+---------+-------+
    | token_id     | varchar(255) | NO   | PRI | NULL    |       |
    | auth_request | blob         | NO   |     | NULL    |       |
    | expiry_time  | datetime     | NO   |     | NUL     |       |
    | token        | blob         | NO   |     | NULL    |       |
    | user_name    | varchar(255) | NO   |     | NULL    |       |
    +--------------+--------------+------+-----+---------+-------+

oauth_refresh_token schema

The following shows the result from the show columns from oauth_refresh_token; command:

    +---------------+--------------+------+-----+---------+-------+
    | Field         | Type         | Null | Key | Default | Extra |
    +---------------+--------------+------+-----+---------+-------+
    | id            | varchar(255) | NO   | PRI | NULL    |       |
    | authorization | blob         | NO   |     | NULL    |       |
    | expiry_time   | datetime     | NO   |     | NULL    |       |
    +---------------+--------------+------+-----+---------+-------+

OpenSSL Commands

The following example openssl command shows generating a client application certificate and private key:

$ openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mykey.pem 
-out mycert.pem
Generating a 1024 bit RSA private key
...................................................................
...........++++++
.....++++++
writing new private key to 'mykey.pem'
-----
You are about to be asked to enter information that will be incorporated 
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank. 
For some fields there will be a default value.
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:MA
Locality Name (eg, city) []:Newton
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Oracle
Organizational Unit Name (eg, section) []:API Gateway
Common Name (eg, YOUR name) []:SampleConfidentialApp
Email Address []:support@widgits.com

OAuth 2.0 Message Attributes

Most of the OAuth 2.0 policy filters in the API Gateway generate message attributes that can be queried further using API Gateway selector syntax. The message attributes generated by the OAuth filters are as follows:

  • accesstoken

  • accesstoken.authn

  • authzcode

  • authentication.subject.id

  • oauth.client.details

accesstoken methods

The following methods are available to call on the accesstoken message attribute:

${accesstoken.getValue()}
${accesstoken.getExpiration()}
${accesstoken.getExpiresIn()}
${accesstoken.isExpired()}
${accesstoken.getTokenType()}
${accesstoken.getRefreshToken()}
${accesstoken.getOAuth2RefreshToken().getValue()}
${accesstoken.getOAuth2RefreshToken().getExpiration()}
${accesstoken.getOAuth2RefreshToken().getExpiresIn()}
${accesstoken.getOAuth2RefreshToken().hasExpired()}
${accesstoken.hasRefresh()}
${accesstoken.getScope()}
${accesstoken.getAdditionalInformation()}

The following example shows output from querying each of the accesstoken methods:

so0HlJYASrnXqn2fL2VWgiunaLfSBhWv6W7JMbmOa131HoQzZB1rNJ
Fri Oct 05 17:16:54 IST 2012
3599
false
Bearer
xif9oNHi83N4ETQLQxmSGoqfu9dKcRcFmBkxTkbc6yHDfK
xif9oNHi83N4ETQLQxmSGoqfu9dKcRcFmBkxTkbc6yHDfK
Sat Oct 06 04:16:54 IST 2012
43199
false
true
https://localhost:8090/auth/userinfo.email
{department=engineering}

accesstoken.authn methods

The following methods are available to call on the accesstoken.authn message attribute:

${accesstoken.authn.getUserAuthentication()}
${accesstoken.authn.getAuthorizationRequest().getScope()}
${accesstoken.authn.getAuthorizationRequest().getClientId()}
${accesstoken.authn.getAuthorizationRequest().getState()}
${accesstoken.authn.getAuthorizationRequest().getRedirectUri()}
${accesstoken.authn.getAuthorizationRequest().getParameters()}

The following example shows output from querying each of the accesstoken.authn methods:

admin
[https://localhost:8090/auth/userinfo.email]
SampleConfidentialApp
343dqak32ksla
https://localhost/oauth_callback
{client_secret=6808d4b6-ef09-4b0d-8f28-3b05da9c48ec, 
  scope=https://localhost:8090/auth/userinfo.email, grant_type=authorization_code, 
  redirect_uri=https://localhost/oauth_callback, state=null, 
  code=FOT4nudbglQouujRl8oH3EOMzaOlQP, client_id=SampleConfidentialApp}

authzcode methods

The following methods are available to call on the authzcode message attribute:

${authzcode.getCode()}
${authzcode.getState()}
${authzcode.getApplicationName()}
${authzcode.getExpiration()}
${authzcode.getExpiresIn()}
${authzcode.getRedirectURI()}
${authzcode.getScopes()}
${authzcode.getUserIdentity()}

The following example shows output from querying each of the authzcode methods:

F8aHby7zctNRknmWlp3voe61H20Md1
sds12dsd3343ddsd
SampleConfidentialApp
Fri Oct 05 15:47:39 IST 2012
599 (expiry in secs)
https://localhost/oauth_callback
[https://localhost:8090/auth/userinfo.email]
admin

oauth.client.details methods

The following methods are available to call on the oauth.client.details message attribute:

${authzcode.getCode()}
${authzcode.getState()}
${authzcode.getApplicationName()}
${authzcode.getExpiration()}
${authzcode.getExpiresIn()}
${authzcode.getRedirectURI()}
${authzcode.getScopes()}
${authzcode.getUserIdentity()}

The following example shows output from querying each of the oauth.client.details methods:

F8aHby7zctNRknmWlp3voe61H20Md1
sds12dsd3343ddsd
SampleConfidentialApp
Fri Oct 05 15:47:39 IST 2012
599 (expiry in secs)
https://localhost/oauth_callback
[https://localhost:8090/auth/userinfo.email]
admin

Example Use

If you add additional access token parameters to the OAuth 2.0 Access Token Info  filter, you can return a lot of additional information about the token. For example:

{  
   "audience" : "SampleConfidentialApp",
   "user_id" : "admin",
   "scope" : "https://localhost:8090/auth/userinfo.email",
   "expires_in" : 3567,
   "Access Token Expiry Date" : "Wed Aug 15 11:19:19 IST 2012",
   "Authentication parameters" : "{username=admin, 
    client_secret=6808d4b6-ef09-4b0d-8f28-3b05da9c48ec, 
    scope=https://localhost:8090/auth/userinfo.email, grant_type=password, 
    redirect_uri=null, state=null, client_id=SampleConfidentialApp, 
    password=changeme}",
   "Access Token Type:" : "Bearer"

You also have the added flexibility to add extra name/value pair settings to access tokens upon generation.The OAuth 2.0 access token generation filters provide an option to store additional parameters for an access token. For example, if you add the name/value pair Department/Engineering to the Client Credentials filter:

Adding Additional OAuth 2.0 Access Token Parameters

You can then update the Access Token Info filter to add a name/value pair using a selector to get the following value:

Department/${accesstoken.getAdditionalInformation().get("Department")}

For example:

Retrieving Parameters from OAuth 2.0 Access Token

Then the JSON response is as follows:

{
  "audience" : "SampleConfidentialApp",
  "user_id" : "SampleConfidentialApp",
  "scope" : "https://localhost:8090/auth/userinfo.email",
  "expires_in" : 3583,
  "Access Token Type:" : "Bearer",
  "Authentication parameters" : 
  "{client_secret=6808d4b6-ef09-4b0d-8f28-3b05da9c48ec, 
    scope=https://localhost:8090/auth/userinfo.email, grant_type=client_credentials, 
    redirect_uri=null, state=null, client_id=SampleConfidentialApp}",
  "Department" : "Engineering",
  "Access Token Expiry Date" : "Wed Aug 15 12:10:57 IST 2012"

You can also use API Gateway selector syntax when storing additional information with the token. For more details on selectors, see Selecting Configuration Values at Runtime.