Acquire access token to call Manager REST API

OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0. In OAuth 2.0 terms, the Manager acts as a resource server when Manager REST API access is attempted.

Therefore, users provisioned within a configured OIDC provider cannot call the Manager REST API using HTTP basic authentication and must instead acquire an access token from the configured OIDC provider. The token must then be presented to the Manager as a bearer token in the HTTP authorization header.

In OAuth 2.0, there are various grant types that an API client can use to acquire an access token from the provider. A common grant type that is used is the Resource Owner Password Credentials (ROPC) grant type. ROPC is similar to HTTP basic authentication in that it requires a user’s credentials. The main difference from an API client’s perspective is that the user’s credentials must first be presented to the configured OIDC provider at the provider’s token endpoint. The provider will then issue an access token to the client which can then be presented to the Manager for REST API access.

Note: The Manager only accepts JWT access tokens. Opaque access tokens will be rejected.

Below is example python code that demonstrates execution of the ROPC flow and a request to the viewSystem.adm Manager REST API method.

import requests

#First, define the parameters required for the ROPC flow. Note that this assumes the provider is configured with the client_secret_post client authentication method.
ropc_parameters = { "grant_type":"password", 
                    "username":"{username}",
                    "password":"{password}", 
                    "scope" : "openid profile email",
                    "client_id":"{client_id}",
                    "client_secret":"{client_secret}"}

#Make the request to the token endpoint.
response = requests.post(url="{token_endpoint}", data = ropc_parameters,timeout=10)

#Extract the access token from the response.
access_token = response.json()["access_token"]

#Make a request to the Manager REST API using the acquired access token.
#Note that verify=False is equivalent to the curl ‘-k’ flag.
view_system_response = requests.get(url="https://{manager.dsnet}/manager/api/json/1.0/viewSystem.adm", headers={"Authorization" : "Bearer " + access_token}, verify=False,timeout=10)

assert view_system_response.status_code == 200

Some providers allow for configurable access policies to also be applied to API clients. In such an environment, no browser exists to prompt a user to respond to an MFA challenge or that a different device context is required. Typically, a provider will document how an API client can satisfy an access policy such as MFA as this requires requests made to provider-specific API methods.

IBM Security™ Verify is a provider that allows API clients to satisfy access policies for an application. Below is a code example of a simple API client satisfying an IBM Security™ Verify MFA access policy for issuance of access tokens that can be presented to the Manager REST API.

import requests
import pyotp

#First, define the parameters required for the ROPC flow. Note that this assumes the provider is configured with the client_secret_post client authentication method.
ropc_parameters = { "grant_type":"password", 
                    "username":"{username}",
                    "password":"{password}", 
                    "scope" : "openid profile email",
                    "client_id":"{client_id}",
                    "client_secret":"{client_secret}"}
                  
#Make the request to the token endpoint.
#This the first factor as the user credentials are included in the POST body.
response = requests.post(url="https://{tenant_url}/v1.0/endpoint/default/token", data = ropc_parameters,timeout=10)

#Extract the mfa_challenge token access token. This token will be rejected.
#by the Manager REST API.
access_token = response.json()["access_token"]

#Call IBM Security Verify's factors API to retrieve all enrollments.
factors_resp = requests.get(url="https://{tenant_url}//v2.0/factors/", headers = {"Authorization" : "Bearer " + access_token},timeout=10)
factors_array = factors_resp.json()["factors"]

#Choose a 2nd factor. Here we use "totp" which is a time-based one-time password.
totp_factor = None
for factor in factors_array:
    if (factor["type"] == "totp"):
        totp_factor = factor
        break

#Construct the totp handler for the user's shared secret key.
totp = pyotp.TOTP("{totp_shared_secret_key}")
query_string = {"returnJwt" : "true"}

#This request is submission of the 2nd factor which is a totp.
response = requests.post(url="https://{tenant_url}/v2.0/factors/totp/" + totp_factor["id"], params=query_string, headers={"Authorization" : "Bearer " + access_token}, json={"otp" : totp.now()},timeout=10)

#If this works, we've successfully achieved MFA through the API. The response contains a JWT we can use in the JWT bearer grant type back at the token endpoint.
assertion = response.json()["assertion"]

jwt_bearer_parameters = { "grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer", 
                    "assertion":assertion,
                    "scope" : "openid profile email",
                    "client_id":"{client_id}",
                    "client_secret":"{client_secret}"}

response = requests.post(url="https://{tenant_url}/v1.0/endpoint/default/token", data = jwt_bearer_parameters,timeout=10)

#This access token can be used for Manager REST API access.
access_token = response.json()["access_token"]

#Make a request to the Manager REST API using the acquired access token.
#Note that verify=False is equivalent to the curl ‘-k’ flag.

view_system_response = requests.get(url="https://{manager.dsnet} /manager/api/json/1.0/viewSystem.adm", headers={"Authorization" : "Bearer " + access_token}, verify=False,timeout=10)

assert view_system_response.status_code == 200

See IBM Security™ Verify documentation for more information on IBM Security™ Verify access policies with API clients.