OpenID Connect

OpenID Connect is an identity layer on top of OAuth2. The differences between the two are:

  • The client must contain the scope openid.

  • The response from the /iroh/oauth2/token will contain not only an access token and a refresh token but also an id_token.

  • The scopes in the access and refresh tokens will behave as if the field allow-partial-user-scopes of your client was true. The scopes will be the biggest intersection between:

    • the user scopes
    • the client scopes
    • the requested scopes

The OpenID specification provides more details about OpenID Connect using Authorization Code Grant Flow.

OpenID Connect provides the ability for a user to grant access to your web application and and it also sends user identity information (email, name, and so on) to your application.

With this workflow, the user will not need to copy or paste any credentials. They just need to click on a button to authorize your client.

An OpenID Connect workflow follows these steps:

  1. Create a single client for your application. This should only be done once.

  2. Generate a link on your web application. When the user clicks on it, they are redirected to IROH, and they can grant access to your application. The user returns to your website with a secret code and you will then retrieve both a refresh token that you should keep securely and an id token.

    Note: This should be done only once per user.

  3. With the refresh token, you can retrieve an access token without user interaction.

    Note: This should be done only when you want to call the API and the access token has expired (every 10 min by default).

  4. The access token can be used to call the IROH APIs on behalf of the user.

    Note: This should be done for all API calls, so we highly recommended that you cache the access tokens and not to call the refresh token for each API call to IROH.

Create a Client

There are two ways to create a client:

  1. Using the Cisco XDR UI
  2. Using the API (via the Swagger UI interface)

Both ways will result in the same outcome. But, before creating the OpenID Connect client, read this section in its entirety to determine the correct client configuration settings.

Mandatory Configuration Settings

  • During client creation, add the openid scope to your client. This will declare the client as an OpenID Connect compatible client.
  • During client creation, you must set the field grants to ["auth-code"] in order to support Authorization Code Grant workflow.
  • If you want to be autonomous, you will need to have control of an HTTPS URL (generally something along https://my.domain.tld/path/to/callback). This is the URL you’ll use to set in the redirects value of the client.

Depending on the information you provide during client creation, the client will not be automatically approved. The client will be approved during creation if all the following conditions are met:

For more details about each field, refer to the section OAuth2 Client Model.

Optional Configuration Settings

  • Provide Access to All Users

    If you need to open your web application to all users and not only to the members of your organization, you will need to create a client with the availability field equal to everyone. The client won’t be approved and you’ll need to reach out to a IROHadministrator to approve it.

  • Redirect to Localhost Without HTTPS

    For clients with availability set to everyone, every URI in the redirects array must be https. If you need to you use another scheme in your URI, then you will need to reach out an administrator to approve your client.

  • Create a Public Client

    If your application is a front-end only application, having a password does not make sense. For this specific case, it is recommended (by the RFC) to not use the Implicit grant. Instead, use an Authorization Code Grant client without any password. In this case you must set the client-type to public.

    This is also a specific need. You will need to request approval from a IROH administrator.

  • Change Access Token Lifetime

    The current default lifetime of access token is 10 minutes. The current default lifetime for refresh token is unlimited.

    If you want a longer lived access token or shorter lived refresh token, you simply need to set the fields access-token-lifetime-in-sec and refresh-token-lifetime-in-sec when creating your client. You will need to request a IROH administrator approve your client.

    Note: After a refresh-token lifetime, the refresh token will no longer work. After half of the lifetime, when getting a new access token, you will also get a newer refresh token with the same lifetime. It is then up to you, the client, to perform a new refresh token call during the second half or 1 hour before the expiration to get a new refresh token. After a new refresh-token is provided, the old one can be revoked anytime so you should cease using the old refresh token.

    Without a valid refresh token you will be forced to reengage the user in an interactive authorization workflow.

    For more details about each field, refer to the section OAuth2 Client Model.

Using the Cisco XDR UI

Before creating a client, make sure to read the Client Configurations in its entirety to determine the correct client configuration settings.

Note: When creating an OAuth Code Client, there is an auto-approve feature if all criteria is met. If some criteria is not met, the client is created but disabled until it has been approved by a user with an Administrator role.

For details on how to create an OAuth Code Client, see the topic in the Cisco XDR Help.

Using the API (via the Swagger UI Interface)

Before creating a client, make sure to read the Client Configurations in its entirety to determine the correct client configuration settings.

The Swagger UI provides raw access to the API to create a client. However, the only way to work with this API is by using a JWT with the oauth scope.

Retrieve the list of your scopes. You will not be able to create a client with more scopes than you are allowed to access.

To get the list of scopes, use the whoami profile API:

https://visibility.amp.cisco.com/iroh/profile/#!/Profile/get_iroh_profile_whoami

If you are already logged in to https://visibility.amp.cisco.com/, you will not need to enter any information in the Authorization header inputs in Swagger. If not, click Authorize and provide authorization with one of the followin: IROH login, apiKey, or OAuth2 credentials.

To use the /iroh/profile/whoami API:

  1. Open the whoami API Swagger UI.

  2. Click Try it out.

  3. Click Execute.

    Under Server response, assuming you received a HTTP status code of 200, you will find the response from the API request. It is a JSON containing your user and org information including the list of your scopes.

Here is example response from the /iroh/profile/whoami API:

{
    "user": {
        "scopes": [
            "admin",
            "casebook",
            "cisco",
            "collect",
            "enrich",
            "global-intel:read",
            "inspect",
            "integration",
            "oauth",
            "private-intel",
            "profile",
            "response",
            "ui-settings"
            "users"
        ],
        "updated-at": "2019-04-30T13:54:21.641Z",
        "user-email": "dev.null@cisco.com",
        "org-id": "13375cf9-561c-4958-0000-6d84b7ef09d4",
        "user-id": "idb-amp:13375ee9-2e3a-4e1b-977d-961facb5fd84",
        "idp-mappings": [{
            "idp": "idb-amp",
            "user-identity-id": "13375ee9-2e3a-4e1b-977d-961facb5fd84",
            "organization-id": "13375cf9-561c-4958-0000-6d84b7ef09d4"
        }],
        "enabled?": true,
        "last-logged-at": [
            "2019-04-30T13:54:21.843Z"
        ],
        "created-at": "2019-04-30T13:54:21.622Z"
    },
    "org": {
        "scim-status": "activated",
        "name": "IROH Testing",
        "enabled?": true,
        "id": "13375cf9-561c-4958-0000-6d84b7ef09d4",
        "created-at": "2019-04-30T13:54:21.634Z"
    }
}

For a description of each field, refer to the User Model section on the Data Model page.

Now that you know which scopes you have access to, you can now create the client.

To create the OAuth2 client, use the clients API:

https://visibility.amp.cisco.com/iroh/oauth2-clients/index.html#/OAuth2Client/post_iroh_oauth2_clients_clients

To use the /iroh/oauth2-clients/clients API:

  1. Open the clients API Swagger UI: https://visibility.amp.cisco.com/iroh/oauth2-clients/index.html#/OAuth2Client/post_iroh_oauth2_clients_clients.

  2. Click Try it out.

  3. Edit the JSON under CreateClientParams with the configuration for the client. For a description of each field, refer to the section OAuth2 Client Model.

  4. Click Execute.

    Under Server response, assuming you received a HTTP status code of 200, you will find the response from the API request. For a description of each field in the response, refer to the section OAuth2 Client Model.

Use the Client

If you have not yet created a client that can be used for Authorization Code Grant, refer to Create a Client.

If you have successfully created the client and it is approved, you should have the following information:

  • client-id
  • client-password
  • redirect-uri; one of the URL(s) you set in the redirects array of the client
  • scopes; the list of scope you’ll ask IROH users to grant to your application. If it is not empty, it must contain openid.

You will also need to know the authorization and token URLs of IROH. You can get them at the metadata endpoint (c.f. OAuth2 Metadata).

Present the URL to the User

The first step is to present the user with the URL (return line here is for readability only):

https://visibility.amp.cisco.com/iroh/oauth2/authorization?
   response_type=code
   &client_id=YOUR_CLIENT_ID
   &redirect_uri=YOUR_REDIRECT_URL
   &scope=LIST_OF_SCOPES_SPACE_SEPARATED
   &state=A_DIFFICULT_TO_GUESS_RANDOM_STRING

The scope query parameter is optional. Without it, the scopes will match those of the client. Once the user clicks on the link, they will be redirected to IROH and asked to grant access to your web application. If the user accepts or refuses, the user will be redirected to the redirect uri with parameters that will contain further information.

Get the Refresh Token

Listen to your redirect_uri and parse the query parameters. An example of the URL the user will be redirected to after granting your app the access would be:

YOUR_REDIRECT_URL?state=A_DIFFICULT_TO_GUESS_RANDOM_STRING&code=SOME_CODE

Then, you must verify that the value of the state is the same one the user has clicked on. (In our example, the state must be A_DIFFICULT_TO_GUESS_RANDOM_STRING).

Next, get the refresh token by using the /iroh/oauth2/token API with the value of the code query parameter in the request parameters.

Here is an example API request to /iroh/oauth2/token using a cURL command:

curl -X POST \
     -u "YOUR_CLIENT_ID:YOUR_CLIENT_PASSWORD" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=authorization_code&redirect_uri=YOUR_REDIRECT_URL&code=SOME_CODE" \
     'https://visibility.amp.cisco.com/iroh/oauth2/token'

The -u is to use Basic Auth, with client-id as user and client-password as password. In order to manually supply the correct header, don’t forget to base64 encode the client_id:client_password string. The following two code examples are interchangeable:

curl -u "client_id:client_password" https://example.com

and

creds=$(echo -n client_id:client_password | base64)
curl -H "Authorization: Basic $creds" https://example.com

It is also important to set the content type to application/x-www-form-urlencoded.

Note: The route does not support parameters sent via a JSON Content-Type (cf. RFC6749 section 4.1.3).

The server should then return a successful response (cf. RFC6749 section 4.1.4):

{
    "access_token":"eyJhbG...",
    "id_token":"eyJhbG...",
    "token_type":"bearer",
    "expires_in":600,
    "refresh_token":"eJJyFFA..."
}

Important: The POST to the /token route exposes your client password, so it must be done server side and not inside the browser.

You should have both an access token and a refresh token. The access token will expire in 600 seconds. But the refresh token does not expire soon. Make sure to save the refresh token for your user. Each time you need a new access token, you will need the refresh token.

Make an API Request Using the Access Token

Now that you have retrieved the access token (which is a JWT), you can make an API request on behalf of the user. However, it will be restricted to the scope they granted your application.

Here is an example request using the access token:

ACCESS_TOKEN="eyJhbGciO..."
curl -X POST \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -d '{"content":"cisco.com"}' \
    'https://visibility.amp.cisco.com}/iroh/iroh-inspect/inspect'

To see an exhaustive list of APIs with links to their swagger UI interfaces and a list of scopes, see Authorization Access / Scopes.

Get a New Access Token

The access token will expire (default is 10 minutes). API access after token expiration will require user interaction. You will need to use the refresh token of the user to get a new access token.

The request to refresh a token uses the same API you used to get it the first time. But instead of using a grant_type of authorization_code, you will use a grant_type equal to refresh_token (cf. RFC6749 section 6).

Example request:

curl -X POST \
     -u "YOUR_CLIENT_ID:YOUR_CLIENT_PASSWORD" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=refresh_token&refresh_token=REFRESH_TOKEN" \
     'https://visibility.amp.cisco.com/iroh/oauth2/token'

The server should then return a successful response:

{
    "access_token":"eyJhbG...",
    "token_type":"bearer",
    "expires_in":600
}

IMPORTANT: The response might also contain a new refresh token along with the new access token. In that case, you must revoke the old refresh token and use the new one instead. IROH might accept the old refresh token for a short period to prevent bugs in distributed environments.

Tutorial

This section provides complete example. The credentials used will not be functional, but you should be able to follow all the steps with your own credentials.

Clone Demo Project

Clone the demo project from: https://github.com/yogsototh/oauth2-client-demo

Serve it to your own domain, possibly in some directory. This tutorial assumes it will be: https://my.domain.tld/ctr-oauth/

If you cannot test directly from your domain and want to test on localhost check the Run Demo on localhost section for instructions.

Create the Client

Use the /iroh/oauth2-clients/clients API to create the client.

Here is an example API request to /iroh/oauth2-clients/clients using a cURL command:

ACCESS_TOKEN="eyJhbGciO..."
curl -X 'POST' \
   \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json' \
    -H 'User-Agent: ob-http' \
    -H 'Authorization: Bearer $ACCESS_TOKEN" \
    -d '{
        "scopes": [ "profile", "inspect", "openid" ],
        "description": "Developer Doc OAuth2 Test Client",
        "redirects": [ "https://my.domain.tld/ctr-oauth/callback.html" ],
        "availability": "org",
        "name": "OAuth2 Developer Doc Test",
        "grants": [ "auth-code" ],
        "client-type": "confidential"
    }' \
    'https://visibility.amp.cisco.com/iroh/oauth2-clients/clients'

The server should then return a successful response:

{
  "scopes": [
    "profile",
    "inspect",
    "openid"
  ],
  "description": "Developer Doc OAuth2 Test Client",
  "approved?": true,
  "redirects": [
    "https://my.domain.tld/ctr-oauth/callback.html"
  ],
  "availability": "org",
  "password": "CrXwg31_vnRHpjPXzgVzUFKHr6RO8GTL-iI8aDeUU3n48NtD7PFLhg",
  "name": "OAuth2 Developer Doc Test",
  "org-id": "f47a89bf-5d2e-4392-b770-000000000000",
  "enabled?": true,
  "grants": [
    "auth-code"
  ],
  "client-type": "confidential",
  "id": "client-3bb1e787-381d-4f12-bf32-e1158f200ddc",
  "approval-status": "approved",
  "owner-id": "f0010924-e1bc-4b03-b600-000000000000",
  "created-at": "2019-07-25T14:15:29.117Z"
}

For a description of each field in the response, refer to the section OAuth2 Client Model.

Configure the Demo

Edit the info.js to look like:

var oauthURLPrefix="https://visibility.amp.cisco.com";
var oauthServerUrl=oauthURLPrefix + "/iroh/oauth2/authorize";
var oauthServerTokenUrl=oauthURLPrefix + "/iroh/oauth2/token";
var resourceProviderTestEndpoint=oauthURLPrefix + "/iroh/profile/whoami" ;
var response_type="code";
var client_id="client-3bb1e787-381d-4f12-bf32-e1158f200ddc";
var client_password = "CrXwg31_vnRHpjPXzgVzUFKHr6RO8GTL-iI8aDeUU3n48NtD7PFLhg";
var redirect_uri="https://my.domain.tld/ctr-oauth/callback.html";
var scopes=[ "profile", "inspect", "openid" ];
var scope=scopes.join(" ");
var state="whatever=";

Run the Demo

  1. Go to the URL where the demo project was served on your domain (or localhost). In this tutorial, it would be https://my.domain.tld/ctr-oauth/index.html.
  2. Click on the link. You will be redirected to IROH
  3. Authorize the client.
  4. Now back at https://my.domain.tld/ctr-oauth/callback.html, you should inspect the request in your browser and play with the demo.
  5. Retrieve the access token and refresh token using the value of the code query parameter.
  6. Get another access token using the refresh token.

Details About Steps in the Demo

While the workflow necessitates user interaction through the browser, we will describe most requests in detail.

  • Code in callback URL

The user interaction is only needed to authorize the client. They will then visit the URL https://my.domain.tld/ctr-oauth/callback.html and pass the query parameters code and state.

Here is an example URL:

https://my.domain.tld/ctr-oauth/callback.html?
  code=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE1NjQxMjk4NDcsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3VzZXJcL2lkIjoiZjAwMTA5MjQtZTFiYy00YjAzLWI2MDAtODljNmNmNTI3NTdjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vcmdcL2lkIjoiZjQ3YTg5YmYtNWQyZS00MzkyLWI3NzAtYWQ0ODIxYTgyYWNmIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwvZ3JhbnQiOiJhdXRoLWNvZGUiLCJqdGkiOiJmMjFiMDU5NS04YzhjLTRkZTktOGI4MS01NWVmZTIwMThlODMiLCJuYmYiOjE1NjQxMjkxODcsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25hbWUiOiJZYW5uIEVzcG9zaXRvIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2NsaWVudFwvaWQiOiJjbGllbnQtM2JiMWU3ODctMzgxZC00ZjEyLWJmMzItZTExNThmMjAwZGRjIiwiaWF0IjoxNTY0MTI5MjQ3LCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9raW5kIjoiY29kZS10b2tlbiJ9.IL5xGEfcwnKpd2KNMyo2_kNtkEsfwTa6vYKJHR6uF3L3CGX7edat_eYXNmLACgamX3pdYfXo8JAHEOvdr7zl6-fLq0SHlFdxy4pbVQbr8gJt6TAZVWgNu8wxJfTzL6-V0oIv6mcYD2NWTXYoA8R19u6iFnOtoTwXVx58Dk2UXQuueHmq2CejpJspGgjChAHsebh1XKl-6uPo7debCQvrzPhB56lGShKT0NgEqT_ZML032iFqGIBHUe6WdlqO_i6ji1-QX3CPmA_rwep7n0h1RuDxWib9YCtwJFh0SO0AQX_bK-0000000000000000000000000000000000000000
  &state=y5jaXNjby5jb21cL2lyb2hcL2lkZW

The code represents an agreement from a IROH user to grant access to your application. Remember OAuth2 Authorization Code Grant is a contract between three entities: your application (the client), the user, and IROH. The code query parameter is a JWT. Once decoded it contains:

{
   "https://schemas.cisco.com/iroh/identity/claims/user/email":"dev.null@cisco.com",
   "https://schemas.cisco.com/iroh/identity/claims/user/scopes":[
       "integration",
       "private-intel",
       "admin",
       "profile",
       "inspect",
       "sse",
       "users",
       "casebook",
       "enrich",
       "oauth",
       "global-intel:read",
       "collect",
       "response",
       "ui-settings"
   ],
   "https://schemas.cisco.com/iroh/identity/claims/user/nick":"Yann Esposito",
   "email":"dev.null@cisco.com",
   "iss":"IROH Auth",
   "https://schemas.cisco.com/iroh/identity/claims/scopes":[
       "profile",
       "inspect",
       "openid"
   ],
   "exp":1564129847,
   "https://schemas.cisco.com/iroh/identity/claims/oauth/user/id":"f0010924-e1bc-4b03-b600-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/org/id":"f47a89bf-5d2e-4392-b770-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/oauth/grant":"auth-code",
   "jti":"f21b0595-8c8c-4de9-8b81-55efe2018e83",
   "nbf":1564129187,
   "https://schemas.cisco.com/iroh/identity/claims/oauth/scopes":[
       "profile",
       "inspect"
   ],
   "https://schemas.cisco.com/iroh/identity/claims/user/name":"Yann Esposito",
   "https://schemas.cisco.com/iroh/identity/claims/user/id":"f0010924-e1bc-4b03-b600-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/oauth/client/id":"client-3bb1e787-381d-4f12-bf32-000000000000",
   "iat":1564129247,
   "https://schemas.cisco.com/iroh/identity/claims/oauth/kind":"code-token"
}

The JWT claims are detailed in the Call the API / JWT section. Note that the JWT contains three different claims related to scopes: the user scopes, the scope the user agreed to grant and the the scopes the client asked for.

Another field to note is the oauth/kind that contains code-token. This JWT can only be used as a temporary code during the OAuth2 workflow.

Also notice the expiration date (exp) is just 10 minutes after the creation date (iat).

IMPORTANT: Your client must check that the state parameter is the same as the state parameter in the link the user clicked on. Each time you present a link to grant your application to a user, you should generate a new strong random string.

  • Get the access and refresh token with the code

With the code token (you don’t need to decode it), you can get a refresh token and an access token.

Here is an example API request to /iroh/oauth2/token using a cURL command (return line here is for readability only):

client_id="client-38bbc74d..."
client_password="FIz1FDf40..."
curl -X POST \
   -u "$client_id:$client_password" \
   -H 'Accept: application/json' \
   -H 'Content-Type: application/x-www-form-urlencoded' \
   -H 'User-Agent: ob-http' \
   -d 'redirect_uri=https%3A%2F%2Fmy.domain.tld%2Fctr-oauth%2Fcallback.html
      &grant_type=authorization_code
      &scope=profile%2533inspect
      &code=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE1NjQxMzA5NTAsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3VzZXJcL2lkIjoiZjAwMTA5MjQtZTFiYy00YjAzLWI2MDAtODljNmNmNTI3NTdjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vcmdcL2lkIjoiZjQ3YTg5YmYtNWQyZS00MzkyLWI3NzAtYWQ0ODIxYTgyYWNmIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwvZ3JhbnQiOiJhdXRoLWNvZGUiLCJqdGkiOiI2NWU4MGE0Yi03YTM2LTQzNDEtOGI0NC0zZTM2MTk4YjRiMTQiLCJuYmYiOjE1NjQxMzAyOTAsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25hbWUiOiJZYW5uIEVzcG9zaXRvIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2NsaWVudFwvaWQiOiJjbGllbnQtM2JiMWU3ODctMzgxZC00ZjEyLWJmMzItZTExNThmMjAwZGRjIiwiaWF0IjoxNTY0MTMwMzUwLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9raW5kIjoiY29kZS10b2tlbiJ9.yrOZloNpYGrs0eIWk9dVl-OoSgnSggTcCGrS-iPyhsefZ48SFeoWYtiktki8-uRi6hCjYwQ7WMOQ-MQ9Fr7w4ELMNZJeBSHZjHFty-wH_Fmx62NkVzdAty9pALD2sgqBMS44NWPlyzni1h7sP7wRRxr70o4XdPZUD-wIyjmM0Ewtf0tB-MEPfdXm51na-xt3RAd_hoCP3CubuSPYCDp9dQ-9AOzAAJfogRGboI_u1I38oMY_x_GRZUdyLdOHvVz4XaoBUfRgwS-C7eVu73ULavfJmd5W4UaO_LNV9oNgxQQD9B9JlLs7dMVzFxe6UaYi8KXUdk-qZRD5Px_lth7uVw'
   'https://visibility.amp.cisco.com/iroh/oauth2/token'

Here is an example response from the /iroh/oauth2/token API:

{
   "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJzdWIiOiJmMDAxMDkyNC1lMWJjLTRiMDMtYjYwMC04OWM2Y2Y1Mjc1N2MiLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE1NjQxMzA5NzMsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3VzZXJcL2lkIjoiZjAwMTA5MjQtZTFiYy00YjAzLWI2MDAtODljNmNmNTI3NTdjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vcmdcL2lkIjoiZjQ3YTg5YmYtNWQyZS00MzkyLWI3NzAtYWQ0ODIxYTgyYWNmIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwvZ3JhbnQiOiJhdXRoLWNvZGUiLCJqdGkiOiI1Y2Y1NGRkMi0zMmNlLTRkOTctODEzYy0wZWFiYzZlZWI1MjEiLCJuYmYiOjE1NjQxMzAzMTMsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25hbWUiOiJZYW5uIEVzcG9zaXRvIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2NsaWVudFwvaWQiOiJjbGllbnQtM2JiMWU3ODctMzgxZC00ZjEyLWJmMzItZTExNThmMjAwZGRjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC92ZXJzaW9uIjoidjEuMjAuMC1kZjgxNGU3YjYyODMwZGRkNTc2ZCIsImlhdCI6MTU2NDEzMDM3MywiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwva2luZCI6ImFjY2Vzcy10b2tlbiJ9.tZ75vCYYst9gSbnZl7LZ3GiVXRpAmOFy9cmUs9wGkSw7XSdRN-4sqwUkcCoNq161piZedf17PrGRMurEtq9x8cW1_YuU_5pi9mDMH1ayQYNXJXkk6G_PJTbzyBLosdp3IAc_GN7DrCZoHx9-oveCy0MfXTbgrjtsx7BoELynECbjTPAfi8CU_rPRCnIyrxLTFMJdqLHsUVP_MDyXEvV43EPw1uRUn9ZBf-dBAswdFsEhH8RF4IFtZyDxb49HTpoWHA54jFWiYAP3cISyS6IKI8H1aVQHAUDbdSzunx0Rp5U9xJysZiAZzVkiSUGTJqXQt_00000000000000000000",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJzdWIiOiJmMDAxMDkyNC1lMWJjLTRiMDMtYjYwMC04OWM2Y2Y1Mjc1N2MiLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE1NjQxMzA5NzMsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3VzZXJcL2lkIjoiZjAwMTA5MjQtZTFiYy00YjAzLWI2MDAtODljNmNmNTI3NTdjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vcmdcL2lkIjoiZjQ3YTg5YmYtNWQyZS00MzkyLWI3NzAtYWQ0ODIxYTgyYWNmIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwvZ3JhbnQiOiJhdXRoLWNvZGUiLCJqdGkiOiI1Y2Y1NGRkMi0zMmNlLTRkOTctODEzYy0wZWFiYzZlZWI1MjEiLCJuYmYiOjE1NjQxMzAzMTMsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25hbWUiOiJZYW5uIEVzcG9zaXRvIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2NsaWVudFwvaWQiOiJjbGllbnQtM2JiMWU3ODctMzgxZC00ZjEyLWJmMzItZTExNThmMjAwZGRjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC92ZXJzaW9uIjoidjEuMjAuMC1kZjgxNGU3YjYyODMwZGRkNTc2ZCIsImlhdCI6MTU2NDEzMDM3MywiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwva2luZCI6ImFjY2Vzcy10b2tlbiJ9.tZ75vCYYst9gSbnZl7LZ3GiVXRpAmOFy9cmUs9wGkSw7XSdRN-4sqwUkcCoNq161piZedf17PrGRMurEtq9x8cW1_YuU_5pi9mDMH1ayQYNXJXkk6G_PJTbzyBLosdp3IAc_GN7DrCZoHx9-oveCy0MfXTbgrjtsx7BoELynECbjTPAfi8CU_rPRCnIyrxLTFMJdqLHsUVP_MDyXEvV43EPw1uRUn9ZBf-dBAswdFsEhH8RF4IFtZyDxb49HTpoWHA54jFWiYAP3cISyS6IKI8H1aVQHAUDbdSzunx0Rp5U9xJysZiAZzVkiSUGTJqXQt_00000000000000000000",
   "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE3NTE0MTQ0MDAwLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb3JnXC9pZCI6ImY0N2E4OWJmLTVkMmUtNDM5Mi1iNzcwLWFkNDgyMWE4MmFjZiIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2dyYW50IjoiYXV0aC1jb2RlIiwianRpIjoiMjc0YjkwYTAtZDlhNi00YmI2LWJiN2UtMDkzYTY4MzllMTUyIiwibmJmIjoxNTY0MTMwMzEzLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9zY29wZXMiOlsicHJvZmlsZSIsImluc3BlY3QiXSwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9uYW1lIjoiWWFubiBFc3Bvc2l0byIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvdXNlclwvaWQiOiJmMDAxMDkyNC1lMWJjLTRiMDMtYjYwMC04OWM2Y2Y1Mjc1N2MiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9jbGllbnRcL2lkIjoiY2xpZW50LTNiYjFlNzg3LTM4MWQtNGYxMi1iZjMyLWUxMTU4ZjIwMGRkYyIsImlhdCI6MTU2NDEzMDM3MywiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwva2luZCI6InJlZnJlc2gtdG9rZW4ifQ.abtBzZmX64XDTB7OJkcyCsOrGnXj-c6tSg89qg9ENnHSeBs-e4AhQMzHO5ZF5Cb4e7c8z34k0gxatuBqLTtLTztV32ktJGZ1IwFA4k7bpPrW1qdrSJQfZjOBBdLG3DSDMqo7dihqh_4VkfZGHDUNfao12xHTXCbzzfKiZNr6f8UJ0lzEvNZ2tQFkIMjdLVrN7OSk5K56-4SwEL6-X7LHRjF8M0FrGq9QU2lztuRyGXfbPOIal4wJdcfZ-Z2S1_fC82y-rE2mEDEX-diCI_oC_01wFiBbklJLoUEYK6Ry0000000000000000000000000000000000000000000000",
   "token_type": "bearer",
   "expires_in": 600,
   "scope": "profile inspect"
}

Notes:

  • The -u of the cURL command automatically encodes the $client_id:$client_password to base64 and adds it to the header as Basic Auth. If the request is not made with cURL, the Authorization header needs to be Basic Auth, which contains Basic followed by a base64 encoded CLIENT-ID:CLIENT-PASSWORD.

  • The body is not JSON. The Content-Type is application/x-www-form-urlencoded.

  • The access token will expires in 600 seconds.

  • Both the access_token and refresh_token are JWT.

  • Refresh Token

The refresh token is a JWT that once decoded contains:

{
   "https://schemas.cisco.com/iroh/identity/claims/user/email":"dev.null@cisco.com",
   "https://schemas.cisco.com/iroh/identity/claims/user/nick":"Yann Esposito",
   "email":"dev.null@cisco.com",
   "iss":"IROH Auth",
   "https://schemas.cisco.com/iroh/identity/claims/scopes":[
       "profile",
       "inspect"
   ],
   "exp":17514144000,
   "https://schemas.cisco.com/iroh/identity/claims/oauth/user/id":"f0010924-e1bc-4b03-b600-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/org/id":"f47a89bf-5d2e-4392-b770-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/oauth/grant":"auth-code",
   "jti":"64aae4a3-b99b-4215-8f63-c8bf46a4d4b5",
   "nbf":1564130650,
   "https://schemas.cisco.com/iroh/identity/claims/user/name":"Yann Esposito",
   "https://schemas.cisco.com/iroh/identity/claims/user/id":"f0010924-e1bc-4b03-b600-000000000000",
   "https://schemas.cisco.com/iroh/identity/claims/oauth/client/id":"client-3bb1e787-381d-4f12-00000000000000000",
   "iat":1564130710,
   "https://schemas.cisco.com/iroh/identity/claims/oauth/kind":"refresh-token"
}

Your application must save this refresh token for this user.

  • Access Token

The access token is also a JWT that you can use to make API requests. In our example, the client asked for the profile scope that grants access to the route /iroh/profile/whoami.

ACCESS_TOKEN="eyJhbGciO..."
curl -X 'GET' \
   -H 'Accept: application/json' \
   -H "Authorization: Bearer $ACCESS_TOKEN" \
   'https://visibility.amp.cisco.com/iroh/profile/whoami'

Here is an example response from the /iroh/profile/whoami API:

{
   "user":{
       "scopes":[
           "integration",
           "private-intel",
           "admin",
           "profile",
           "inspect",
           "iroh-auth",
           "sse",
           "users",
           "cisco",
           "casebook",
           "enrich",
           "oauth",
           "global-intel:read",
           "collect",
           "response",
           "ui-settings"
       ],
       "updated-at":"2019-07-25T14:53:21.721Z",
       "user-email":"dev.null@cisco.com",
       "user-name":"Yann Esposito",
       "org-id":"f47a89bf-5d2e-4392-b770-000000000000",
       "user-id":"f0010924-e1bc-4b03-b600-000000000000",
       "idp-mappings":[
           {
               "idp":"idb-amp",
               "user-identity-id":"f0010924-e1bc-4b03-b600-000000000000",
               "organization-id":"f47a89bf-5d2e-4392-b770-000000000000"
           }
       ],
       "enabled?":true,
       "last-logged-at":[
           "2019-07-25T14:53:22.183Z",
           "2019-07-25T13:05:50.488Z",
           "2019-07-19T14:37:09.021Z",
           "2019-07-18T12:11:51.297Z",
           "2019-07-12T14:58:36.694Z"
       ],
       "created-at":"2018-09-21T14:52:38.079Z",
       "user-nick":"Yann Esposito"
   },
   "org":{
       "scim-status":"activated",
       "name":"Cisco - IROH Team",
       "updated-at":"2019-07-22T15:27:10.845Z",
       "enabled?":true,
       "additional-scopes":[
           "integration",
           "admin",
           "sse"
       ],
       "settings":{
           "allow-all-role-to-login":false
       },
       "id":"f47a89bf-5d2e-4392-b770-000000000000",
       "created-at":"2018-09-06T04:44:12.512Z"
   }
}
  • Get a new access token with the refresh token

After a few minutes (10 by default), the access token will expire. At that time, you’ll need to get a new access token, but you shouldn’t ask the user to authorize your application again in IROH.

You can get a new access token by using the /iroh/oauth2/token API with the refresh token for that user and your client credentials (return line here is for readability only):

client_id="client-38bbc74d..."
client_password="FIz1FDf40..."
curl -X POST \
   -u "$client_id:$client_password" \
   -H 'Accept: application/json' \
   -H 'Content-Type: application/x-www-form-urlencoded' \
   -H 'User-Agent: ob-http' \
   -d 'grant_type=refresh_token
      &scope=profile%2533inspect
      &refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE3NTE0MTQ0MDAwLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb3JnXC9pZCI6ImY0N2E4OWJmLTVkMmUtNDM5Mi1iNzcwLWFkNDgyMWE4MmFjZiIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2dyYW50IjoiYXV0aC1jb2RlIiwianRpIjoiMjc0YjkwYTAtZDlhNi00YmI2LWJiN2UtMDkzYTY4MzllMTUyIiwibmJmIjoxNTY0MTMwMzEzLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9zY29wZXMiOlsicHJvZmlsZSIsImluc3BlY3QiXSwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9uYW1lIjoiWWFubiBFc3Bvc2l0byIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvdXNlclwvaWQiOiJmMDAxMDkyNC1lMWJjLTRiMDMtYjYwMC04OWM2Y2Y1Mjc1N2MiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL29hdXRoXC9jbGllbnRcL2lkIjoiY2xpZW50LTNiYjFlNzg3LTM4MWQtNGYxMi1iZjMyLWUxMTU4ZjIwMGRkYyIsImlhdCI6MTU2NDEzMDM3MywiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwva2luZCI6InJlZnJlc2gtdG9rZW4ifQ.abtBzZmX64XDTB7OJkcyCsOrGnXj-c6tSg89qg9ENnHSeBs-e4AhQMzHO5ZF5Cb4e7c8z34k0gxatuBqLTtLTztV32ktJGZ1IwFA4k7bpPrW1qdrSJQfZjOBBdLG3DSDMqo7dihqh_4VkfZGHDUNfao12xHTXCbzzfKiZNr6f8UJ0lzEvNZ2tQFkIMjdLVrN7OSk5K56-4SwEL6-X7LHRjF8M0FrGq9QU2lztuRyGXfbPOIal4wJdcfZ-Z2S1_fC82y-rE2mEDEX-diCI_oC_01wFiBbklJLoUEYK6RylEQ9lIMgYsUNsw07nM3IWua2cq5O6rNWEe9yJJzo5TIuQg'
   'https://visibility.amp.cisco.com/iroh/oauth2/token'

Here is an example response from the /iroh/oauth2/token API:

{
   "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL2VtYWlsIjoieWFlc3Bvc2lAY2lzY28uY29tIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9zY29wZXMiOlsiaXJvaC1hZG1pbiIsImludGVncmF0aW9uIiwicHJpdmF0ZS1pbnRlbCIsImFkbWluIiwicHJvZmlsZSIsImluc3BlY3QiLCJpcm9oLWF1dGgiLCJzc2UiLCJ1c2VycyIsImNpc2NvIiwiY2FzZWJvb2siLCJvcmJpdGFsIiwiZW5yaWNoIiwib2F1dGgiLCJnbG9iYWwtaW50ZWwiLCJjb2xsZWN0IiwicmVzcG9uc2UiLCJ1aS1zZXR0aW5ncyJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25pY2siOiJZYW5uIEVzcG9zaXRvIiwiZW1haWwiOiJ5YWVzcG9zaUBjaXNjby5jb20iLCJzdWIiOiJmMDAxMDkyNC1lMWJjLTRiMDMtYjYwMC04OWM2Y2Y1Mjc1N2MiLCJpc3MiOiJJUk9IIEF1dGgiLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJleHAiOjE1NjQxMzQxODksImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3VzZXJcL2lkIjoiZjAwMTA5MjQtZTFiYy00YjAzLWI2MDAtODljNmNmNTI3NTdjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vcmdcL2lkIjoiZjQ3YTg5YmYtNWQyZS00MzkyLWI3NzAtYWQ0ODIxYTgyYWNmIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwvZ3JhbnQiOiJhdXRoLWNvZGUiLCJqdGkiOiIzNmY4YzgxNi1jN2E1LTQ0ZWMtYWZhNS1iMDI4OGIzMzJkZDkiLCJuYmYiOjE1NjQxMzM1MjksImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL3Njb3BlcyI6WyJwcm9maWxlIiwiaW5zcGVjdCJdLCJodHRwczpcL1wvc2NoZW1hcy5jaXNjby5jb21cL2lyb2hcL2lkZW50aXR5XC9jbGFpbXNcL3VzZXJcL25hbWUiOiJZYW5uIEVzcG9zaXRvIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC91c2VyXC9pZCI6ImYwMDEwOTI0LWUxYmMtNGIwMy1iNjAwLTg5YzZjZjUyNzU3YyIsImh0dHBzOlwvXC9zY2hlbWFzLmNpc2NvLmNvbVwvaXJvaFwvaWRlbnRpdHlcL2NsYWltc1wvb2F1dGhcL2NsaWVudFwvaWQiOiJjbGllbnQtM2JiMWU3ODctMzgxZC00ZjEyLWJmMzItZTExNThmMjAwZGRjIiwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC92ZXJzaW9uIjoidjEuMjAuMC1kZjgxNGU3YjYyODMwZGRkNTc2ZCIsImlhdCI6MTU2NDEzMzU4OSwiaHR0cHM6XC9cL3NjaGVtYXMuY2lzY28uY29tXC9pcm9oXC9pZGVudGl0eVwvY2xhaW1zXC9vYXV0aFwva2luZCI6ImFjY2Vzcy10b2tlbiJ9.t8f5cwIBYMYlKSewpCAv2Sgh3xOhQS_MkQqFd14Xz2j9eZD_SpfLRSdYCt5glW9NMiMuUHqtzkYroK46zYeFpy5XoEx3gLZLJC4eJaVdIxRqRxt2IcJ5F7R31Xt_R5Cbkrgncl6NxynTeRyb--4UoQXlTVNmwXQxEGbM1bc9EU7iFabevJVswpj_no9Ah5zp2-BRtvszPzuF9-Ii5AUwmsAoVziH--uezFQQv5xhQNBA17fXjIn5D3oBiK50_vZEaAgdHE3SLDDPqw4BiPzeNipvE6oGuA486Bo3XET_O7DkgzzsEakwZe2HF2DKAstBLJSeMdRjA-fhBrRCLxHJSQ",
   "token_type": "bearer",
   "expires_in": 600,
   "scope": "profile inspect"
}

This is a very similar request to the one that was used with the code token. The only differences are:

  • It uses the refresh_token instead of the code token.
  • It uses the refresh_token for the grant_type parameter.

You must use Basic Auth with your client id and password for authorization, and specify a Content-Type of application/x-www-form-urlencoded.

Run Demo on localhost

For security, IROH does not allow clients with non https redirect URIs to be approved automatically.

In order to serve HTTPS locally, you should follow the instructions to create a new self signed certificate.

git clone https://github.com/yogsototh/oauth2-client-demo
cd cert
./gen-new-root-cert.sh
./gen-new-cert.sh rootCA
cd ..

You should serve the site/ directory using the created server.crt and server.key.

A possible tool is sws. The easiest way to install it is to first install stack and then execute stack install sws.

You may also need to modify your browser to trust the self-signed certificate.

Checklist

⚠ To verify your integration, follow the Client Checklist.