Authorization (Auth) Code Flow

Introduction

This page describes how to implement the Authorization (Auth) Code Flow in Centrify. For an overview of this flow see OAuth Clients.

Overview

Six steps are required to enable your client applications to use OAuth 2.0 when accessing Centrify endpoints:
Step 1: Create a New OAuth App in the Admin Portal
Step 2: Configure the newly created OAuth 2.0 Client.
Step 3: (Optional) Set up Tokens.
Step 4: (Optional) Create Scopes.
Step 5: Create a Confidential Client.
Step 6. Verify Role Access.
Step 7. Develop a Client.

Enabling a Client Application Access to Centrify

The steps below are to be used for web applications that require OAuth2 authentication but are not in the Application Catalog.

Step 1: Create a New OAuth App in the Admin Portal

The first step in enabling your client applications to use OAuth 2 when accessing Centrify endpoints, is to create a new OAuth Client on the Admin Portal:

  1. Log in to your tenant.
  2. Navigate to your user name at the top right corner and select Switch to Admin Portal from the dropdown:
951
  1. Click Skip on the Quickstart splash screen if it appears.
  2. Click Apps in the Dashboard.
  3. Click Add Web Apps and select the Custom tab on the Add Web Apps popup.
  4. Locate OAuth2 Client in the list and click Add. This creates an OAuth2 Client for use with the Centrify APIs.
  5. Click Yes on the Add Web App popup that appears.
  6. Click Close on the Add Web Apps popup. The app configuration screen is displayed.

Step 2. Configure the new OAuth 2.0 Client

  1. In the app configuration screen (left side), select categories (listed below).
  2. For each category, enter the appropriate data in the fields.
  3. Click Save.
858

Note: You can create multiple OAuth 2.0 clients on the Admin Portal and configure each of them differently to serve different clients. For example, you can configure the supported OAuth 2.0 flows and scopes differently.

Description:

  • Application ID: the tenant portion of the URL for OAuth endpoints. Note that this value cannot contain spaces.
  • Application Name: a descriptive name for the application.
  • Application Description: a description of the application (not seen by users).
  • Category: the default grouping for the app on the Admin Portal.

General Usage: specifies the types of credentials that can be used to authorize with this client:

  • Client ID Type: Set to Anything for the Authorization Code flow.
    Confidential is recommended for all flows in which the user provides their username and password and the client sends a client ID and secret. If you select this option, populate the remaining configuration elements (listed below) and then proceed to Create a Confidential Client.

Issuer: the URL of the server issuing access tokens. Can be left as default.

Allow Redirects: specifies the redirects that should be trusted when redirection occurs during an Authorization Code flow.

Tokens:

  • Token Type: specifies the type of token to issue (JwtRS256 or opaque). JwtRS256 is a JSON Web Token (JWT) composed of Base64-encoded user and claim information. An opaque token contains no information about the user. To obtain user and claim information for an opaque token an introspection URL must be used by passing the token.
  • Auth Methods: specifies the authentication flow(s) for which the specified token type should be issued. Set to Auth Code.
  • Token Lifetime: specifies the duration of the token's lifespan.
  • Issue refresh tokens: when enabled, allows clients to request a refresh token that can be exchanged for a new access token.

Scope:

  • User must confirm authorization request: when enabled, this setting requires that the client display a popup where the user must select and approve the scope(s) to allow for the client.
  • Scope Definitions: allows one or more scopes to be specified for authorization by the client. Scopes must first be defined through the scope configuration screen as described here.

For more information see Create Scopes below.

User Access: specifies the role(s) that the user must be in, in order to authorize.

Changelog: lists changes made to the client.

Step 3. Set up Tokens

  1. Navigate to Apps and select the application to set the token for.
  2. Click on Token:
579
  1. Select a token type from the Token Type dropdown.
  2. Set the Auth Methods field to Auth Code.
  3. (Optional) Configure the Token Lifetime.
  4. (Optional) Enable refresh tokens and set the Refresh token lifetime.

Step 4. Create Scopes

A scope is a named entity which defines the endpoint(s) that a client may access. Scopes are used in flows where the user is prompted to grant scope authorization, as well as for confidential clients where there is no popup for the user to approve authorization. Defining scopes through the Admin Portal lowers the risk associated with traditional service accounts by scoping the authorization to specific APIs. This ensures the application will only be able to access resources for the scopes assigned to the client through the Admin Portal.

Note: the user must be in a role that gives them access to use the API’s that the server is scoped to.

Use the following steps to define scopes for an OAuth2 Client:

Note: this step may be performed before or during the configuration of the OAuth 2 Client.

  1. Click on Scope:
1008
  1. Click Add.
  2. Enter a unique name for the new scope, and optionally a description.
  3. Click Add and enter the endpoint suffix. Note that the wildcard "*" character can be used to specify multiple endpoints. Repeat this step to add additional entries:
507

Note: to add a scope for all APIs, enter .* for the REST Regex value.

  1. Click Save to save the new scope definition and close the popup.

Step 5. Create a Confidential Client

Note: the user interface and workflow described in this section will change significantly in the near future.

If you selected Confidential as the web application Client ID Type during configuration, continue with this procedure. To authorize a confidential client (that is, a client that provides a client ID and client secret), you must create a user entity representing the confidential client.

  1. Navigate to General Usage tab, click the Click here to create one link, and save any changes if prompted:
847
  1. Enter the application's client ID into the Login Name field.
  2. Enter values into the Email Address and Display Name fields. Confidential clients do not use these values, but they are required in order to satisfy the required fields of the user form.
  3. Enter the application's client secret into the Password and Confirm Password fields.
  4. Navigate to the Status section at the bottom and enable Is OAuth confidential client.
  5. Click Create User. A confidential client who specifies the client ID and secret can now authorize against your Centrify Tenant.

Step 6. Verify Role Access

In order for an application to authenticate the client credentials created in the previous step, you must ensure that the service user created in the previous step is part of a role that has access to the app.

  1. Navigate to the Roles tab, select a role that will be associated with the client application and add the user created in the previous step to the role.
  2. Navigate back to the Apps tab and select the application.
  3. Navigate to the User Access tab, ensure that the role is listed, and click Save if you add a role.

Step 7. Develop a Client

This section illustrates one way to approach client application development. It draws on key components of the Centrify.Samples.PowerShell example client application, available on GitHub. The following procedure and code samples provide a brief walk through of the example project and the key files to examine.

Behind the Scenes

Before examining the PowerShell script, it's useful to understand the underlying Centrify APIs that will be invoked by PowerShell to perform the Auth Code Flow.

The first endpoint to be invoked is the /oauth2/authorize/ endpoint. The response_type is set to code to indicate that an authorize code should be returned:

GET https://mytenant.centrify.com/oauth2/authorize/myapplication?debug=true&scope=all&response_type=code&redirect_uri=https://mytenant.centrify.com/sysinfo/dummy&[email protected]&client_secret=abc123

The response contains HTML with a redirect URI to a login page:

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="/login?cloudRedirect=Oauth2%2FAuthorize%2Fmyapplicaton%3Fbounce%3DbCFgyPpOcEyohZhj6QD...">here</a>.</h2>
</body></html>

Next the client invokes the redirect URI on the tenant which returns the HTML necessary to render the login page:

GET https://mytenant.centrify.com/login?cloudRedirect=Oauth2%2FAuthorize%2Fmyapplication%3Fbounce%3DbCFgyPpO...

As the user authenticates through the login page, the Start Authentication and Advance Authentication endpoints are invoked.

When the user successfully fulfills the security challenge(s), the /oauth2/authorize/{app ID} endpoint is invoked again. This time, the response contains an authorization code in the code query parameter of the redirect URI returned:

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="https://mytenant.centrify.com:443/sysinfo/dummy?responseType=code&amp;code=HsOynOzaKL_yCo_-cJhh4x....">here</a>.</h2>
</body></html>

The client then invokes the redirect URI with the access code, by specifying code for the response_type query parameter, and the access code for the code query parameter:

GET https://mytenant.centrify.com/sysinfo/dummy?responseType=code&code=HsOynOzaKL_yCo_-cJhh4x... HTTP/1.1

The client invokes the /token/ endpoint to exchange the access code for an access token by passing the full redirect URI in the redirect_uri parameter using form serialization. The access code is specified in the URI's code query parameter and the grant_type is set to authorization_code:

POST https://mytenant.centrify.com/oauth2/token/myapplication HTTP/1.1
Content-Type: application/x-www-form-urlencoded


redirect_uri=https%3A%2F%2Faaa3226.mytenant.com%2Fsysinfo%2Fdummy&code=HsOynOzaKL_yCo_-cJhh4xM...&grant_type=authorization_code

The response contains the access token and a refresh token:

{  
   "access_token":"eyJhbGciOiJSU...",
   "token_type":"Bearer",
   "refresh_token":"oXSi9unNG0eUDh...",
   "expires_in":18000,
   "scope":"all"
}

The token can then be used in subsequent API calls by including it in the Authorization header along with the type of token. For example:

POST https://mytenant.centrify.com/security/whoami HTTP/1.1

Authorization: Bearer eyJhbGciOi...

Try the API in Postman:
Try the API in Postman.
Click here for help with using our sample Postman collection.

Prepare the PowerShell Script

  1. Download the example client application from GitHub.

  2. Navigate to the centrify-samples-powershell folder and open Centrify.Samples.PowerShell.Example.ps1 in a text editor.

  3. Comment out the line which makes the username mandatory as well as $username and modify the $endpoint parameter to point to your tenant's base URL and save the file:

[CmdletBinding()]
param(
    #Used for interactive auth only. Comment out for OAuth
    #[Parameter(Mandatory=$true)]
    #[string]$username = "",
    [string]$endpoint = "https://cloud.centrify.com" <- modify this.
)
  1. Set the Appid, Clientid, Clientsecret, and Scope parameters in the call to Centrify-OAuth-ClientCredentials based on how they were set on the Admin Portal, and save the file:
$token = Centrify-OAuthCodeFlow -Endpoint $endpoint -Appid "myapplication" -Clientid "[email protected]" -Clientsecret "abc123" -Scope "all" -Verbose:$enableVerbose
  1. Navigate to the module subfolder and open Centrify.Samples.PowerShell.psm1.

  2. Locate the Centrify-OAuthCodeFlow function, modify $endpoint to point to your tenant's base URL, and save the file:

function Centrify-OAuthCodeFlow()
{

    [CmdletBinding()]
        param(
        [string] $endpoint = "https://cloud.centrify.com", <- modify this
        [Parameter(Mandatory=$true)]
        [string] $appid, 
        [Parameter(Mandatory=$true)]
        [string] $clientid,
        [Parameter(Mandatory=$true)]
        [string] $clientsecret,
        [Parameter(Mandatory=$true)]
        [string] $scope
    )
  1. Open Powershell and navigate to the centrify-samples-powershell folder.

  2. Execute the Powershell script Centrify.Samples.PowerShell.Example.ps1 using the following command:

./Centrify.Samples.PowerShell.Example.ps1

The PowerShell example will display a login screen where the user can enter their credentials to grant access. Upon successfully authenticating, the example generates and displays an access token.

A Closer Look at Centrify-OAuthCodeFlow

The steps above used the function Centrify-OAuthCodeFlow to perform OAuth2 authentication which returned an access token. That function is defined in \centrify-samples-powershell-master\module\Centrify.Samples.PowerShell.psm1 and contains all of the functionality to invoke the /oauth/token endpoint.

This section takes a closer look at how that function works.

The function starts with the parameter definitions which include a default endpoint, and mandatory parameters for the application ID, client ID, client secret, and the name of the desired scope to access:

function Centrify-OAuthCodeFlow()
{

    [CmdletBinding()]
        param(
        [string] $endpoint = "https://cloud.centrify.com",
        [Parameter(Mandatory=$true)]
        [string] $appid, 
        [Parameter(Mandatory=$true)]
        [string] $clientid,
        [Parameter(Mandatory=$true)]
        [string] $clientsecret,
        [Parameter(Mandatory=$true)]
        [string] $scope
    )
    ...

The function then sets $verbosePreference to Continue which ensures that all output is displayed on screen. This is followed by construction of the full paths to the authorization and token endpoints which are stored in $authUri and $tokUri respectively:

...
$config = @{}
$config.authUri = "$endpoint/oauth2/authorize/$appid"
$config.tokUri = "$endpoint/oauth2/token/$appid"
$config.redirect = "$endpoint/sysinfo/dummy"	
$config.clientID = $clientid
$config.clientSecret =  $clientsecret
$config.scope = $scope
...

The function calls centrify-InternalOAuthCodeFlow which performs the bulk of the endpoint calls and stores the access token returned in $restResult. This is then combined with the redirect endpoint and returned to the caller through $finalResult:

...
$restResult = centrify-InternalOAuthCodeFlow $config

$finalResult = @{}
$finalResult.Endpoint = $endpoint    
$finalResult.BearerToken = $restResult.access_token

Write-Output $finalResult  
...

Use the Access Token in Subsequent Requests

Once you verify that an access token can be successfully returned with the PowerShell script, you can then uncomment subsequent requests in the script that will use the access token. For example, to use the /Security/whoami endpoint which indicates who the current user is, uncomment the following lines in Centrify.Samples.PowerShell.Example.ps1:

$userInfo = Centrify-InvokeREST -Endpoint $token.Endpoint -Method "/security/whoami" -Token $token.BearerToken -Verbose:$enableVerbose     

Write-Host "Current user: " $userInfo.Result.User

Inspect the Client's Traffic in Fiddler

Using a network inspection tool is an excellent way to view the OAuth 2 calls being made behind the scenes.

This section provides a brief walkthrough of viewing the network traffic from the example PowerShell above using Fiddler, a popular network traffic analysis tool. See Using Trace Tools for more information about using Fiddler to analyze network traffic between a Centrify client and tenant.

  1. Run Fiddler.
  2. Open PowerShell and run sample.ps1.
  3. Return to Fiddler and select the /oauth2/authorize/<your application> call in the left pane.
  4. Select the Raw tab for the request in the upper region of the right pane. This shows the first call made by the client application:
1391

In the screenshot above, a request is made to the authorization endpoint. The response the URI to redirect the user to the login screen.

  1. Select the /login call in the left-hand pane:
1394
  1. Select Raw tab for the response in the lower region of the right pane to see the response:
HTTP/1.1 200 OK
...


<!DOCTYPE html>
<html>
<head>
    <!-- Page setup -->
    <title>User Portal</title>
    <meta http-equiv="X-UA-Compatible" content="IE=8,9,10" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <link rel="shortcut icon" href="/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/images/logos/centrify-16-1.png"/>

    <!-- CSS includes -->
    <link href='/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/fonts/Roboto.css?_ver=1523995839' rel='stylesheet' type='text/css'>
    <link href='/vfslow/lib/ui/../uibuild/compiled/centrify/production/resources/fonts/Icon-Set.css?_ver=1523995839' rel='stylesheet' type='text/css'>
    <link href='/vfslow/lib/ui/../uibuild/standalonelogin/login.css?_ver=1523995839' rel='stylesheet' type='text/css'>

    <!-- Window style -->
    <style type="text/css">
        embed {display:none; width:0; height:0; padding:0; margin:0;}
        html,
...

The response contains the HTML necessary to display a popup window that renders the login page.

  1. Select the second call to /oauth2/token/<application> in the left pane.
1392

The request to exchange the access code for an access token is shown in the right pane. Subequent endpoints can now be invoked using that access token such as /security/whoami as shown in the screenshot above.