Policy-based user self care - factors enrollment

Introduction

While IBM Security Verify provides its own User Self Care (USC) experience, it is not uncommon or unreasonable for adopters to provide their own customized USC user experience and multi factor (MFA) enrollments and registration. MFA enrollment is a critical moment for enabling strong and highly trusted authentication and identity assurance capabilities to you users. As such, the enrollment "ceremonies" must be performed using highly trusted application components that adhere to least privilege and drive users to a high level of trusted identity assurance. This article will provide advice on how this can be achieved using IBM Security Verify features such as restricted API entitlements and access policy enabled authentication and authorization.

This article expands on advice and guidance provided at the following locations:

This article does not provide a fully featured USC application but rather provides advice, recommendations and some example API calls that could assist the design and implementation of such an application

General Approach

The context of this article is a custom USC application that can enable end users to self manage their enrolled MFA factors. However, no USC capability exists without a sound initial user onboarding component. As will be seen later, the initial onboarding process will need to ensure that users have an enrolled email or SMS factor. This is needed because an access policy will be applied to our USC application that will require our users to satisfy an MFA authentication prior to managing any other aspect of their enrolled MFA state or indeed to enroll any additional MFA factors. The minimal factors acceptable for this purpose will be email OTP or sms OTP.

Given that a process for initial user onboarding is in place the main components of a secure USC solution to enable end user self management of MFA enrollments will include:

  • A custom OIDC application in the IBM Security Verify tenant
  • Enabling and configuring a minimal set of API entitlements that enable users to manage their own MFA enrollments
  • Definition of an access policy that requires users to successfully complete an MFA authentication with an available factor. This access policy will ensure that entitled access tokens are not granted unless an MFA step up has been successful.
  • Apply the policy to the custom OIDC application
  • Implement the custom USC application such that the following are supported
    • Initial access token grant where its response indicates an MFA is required. This is driven by access policy.
    • Complete an MFA flow using one of the users available factors. The result of this flow will be a JWT that may be exchanged for a fully entitled and authorized access token
    • Exchange the JWT returned from MFA completion for a fully entitled access token
    • Perform MFA enrollment management functions using fully entitled access token.

User On Boarding

User on boarding is not a topic covered in detail by this article, however a few points are worthy of mention and consideration.

  • IBM Security Verify offers a few solutions and components that enable user account records to be created and updated in the tenant cloud directory.
    • SCIM API's enable custom applications to manage user account records
    • LDAP Directory Sync - enables records to synchronized between cloud directory and an external identity store.
    • Just In Time Provisioning can be performed during SSO federation flows or On Prem authentication bridge flows.
  • The USC application described in the article will require that users perform some kind of MFA authentication prior to obtaining a fully authorized access token which may then manage other enrolled MFA factors. email OTP or sms OTP will be the minimum acceptable MFA factors.
    • The on boarding application will need to enroll an OTP or other factor on the users behalf after vetting and validating the new user
    • The on boarding application will likely use a client credentials flow to obtain an access token with the following API entitlements
      • Authenticate any user
      • Manage authenticator registrations for all users
      • Manage second factor enrollments for all users
      • Manage users and standard groups

An example SCIM API representation of a user of our USC application is shown below.

{
    "emails": [
        {
            "type": "work",
            "value": "[email protected]"
        }
    ],
    "name": {
        "formatted": "Jessica Breton",
        "familyName": "Breton",
        "givenName": "Jessica"
    },
    "active": true,
    "id": "6070004YSH",
    "externalId": "[email protected]",
    "password": "{{enduser_password}}",
    "userName": "jessica",
    "phoneNumbers": [
        {
            "type": "work",
            "value": "99999999"
        }
    ],
    "urn:ietf:params:scim:schemas:extension:ibm:2.0:Notification": {
        "notifyType": "EMAIL",
        "notifyPassword": false,
        "notifyManager": false
    },
    "urn:ietf:params:scim:schemas:extension:ibm:2.0:User": {
        "realm": "cloudIdentityRealm",
        "userCategory": "regular"
    },  
    "schemas": [
        "urn:ietf:params:scim:schemas:extension:ibm:2.0:Notification",
        "urn:ietf:params:scim:schemas:extension:ibm:2.0:User",
        "urn:ietf:params:scim:schemas:core:2.0:User"
    ]
}

Example CURL request and response to enroll the new users SMS OTP factor is shown below:

curl --location --request POST 'https://<tenant>/v2.0/factors/smsotp' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer yYWaV07kdJMnsHNgDdH0SfeTlbzROasQwZlwBYDm' \
--data-raw '{
  "enabled": true,
  "userId": "6070004YSH",
  "phoneNumber": "99999999"
}'

Response:

{
    "id": "59aeb30c-02b3-4602-bf70-c8005b9f8cde",
    "userId": "6070004YSH",
    "type": "smsotp",
    "created": "2021-06-11T08:13:34.732Z",
    "updated": "2021-06-11T08:13:34.732Z",
    "enabled": true,
    "validated": false,
    "attributes": {
        "phoneNumber": "99999999"
    }
}

Custom USC Application Configuration

In order to invoke the MFA enrollment and end user management functions of an IBM Security Verify tenant, an access token with sufficient API entitlement permissions is needed. An OIDC application configuration is needed in the IBM Security Verify tenant. Some of the key configuration items for this custom USC application are shown in the following sections.

Grant types and JWT settings

The custom USC application will use the Resource Owner Password Credential (ROPC) flow to obtain an authorized token for subsequent API calls to MFA enrollment management endpoints. This will also serve as a first factor authentication. The jwt-bearer grant also needs to be enabled. This grant is used to obtain an fully authorized access token after an MFA authentication has been performed. The MFA step up is required as part of the access policy that will be protecting this application.

OIDC ConfigurationOIDC Configuration

OIDC Configuration

Protect the OIDC application with an MFA access policy

The diagram below illustrates the access policy configuration settings that will be applied to access token grant requests at runtime. A custom access policy named Custom USC Policy has been created in the Policy Editor. This is described in a later section. The access policy will be evaluated and applied during ROPC and JWT Bearer grant requests.

Set application access policySet application access policy

Set application access policy

Restrict API access for least privilege

The purpose of this custom USC application is to provide a specific user experience to end users enabling them to manage their enrolled MFA factors. By default, all custom OIDC applications are granted the complete set of User Permissions shown in the Edit API client diagram below. In many cases this over privileges custom OIDC applications. It is best practice to limit permissions as much as possible. This can be achieved by selecting the minimum subset of API permissions required by the application. In the case of this USC application that subset is represented by those permissions shown and selected in the diagrams below.

View API permissionsView API permissions

View API permissions

Edit API PermissionsEdit API Permissions

Edit API Permissions

Custom Access Policy

The access policy for this USC application is relatively simple. It requires completion of a first factor. This will be achieved via the ROPC flow at runtime. It then has one policy rule, the default, which requires successful completion of an MFA per session. Per session in this case will be per token grant.

The first contact rule is shown below.

First contact ruleFirst contact rule

First contact rule

The MFA per session rule is embodied by the default rule as show in the diagrams below.

Policy rule listPolicy rule list

Policy rule list

Update default ruleUpdate default rule

Update default rule

USC Access Token with Policy Authentication

With the OIDC application configuration defined in the IBM Security Verify tenant, the implementation of the USC application can proceed. This section will illustrate the type of flows and API calls needed to obtain a fully entitled access token after completion of a successful MFA.

The basic steps include:

  • Initiate an ROPC grant flow
  • Use the resulting restricted access token to complete an MFA step up flow
  • Exchange the JWT from the step up for a fully entitled access token
  • Complete a TOTP enrollment with the fully entitled access token

Initial Grant

The USC application will need to present an username and password login screen to the user. After collecting the user credentials, the USC application may attempt the initial ROPC flow as a way to verify the users credentials and obtain an access token.

The curl example below shows the initial ROPC flow. Noteworthy points here include:

  • Authorization header is HTTP Basic authorization where the value is the clientId and secret of the custom OIDC application.
curl --location --request POST 'https://<tenant>/v1.0/endpoint/default/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Accept: application/json' \
--header 'Authorization: Basic N2ExZjA3NzQtOTgyNy00YjhiLWI4NTItNjRhNTJkNTFjMjhlOm9hcTFqa0JLU0c=' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=jessica' \
--data-urlencode 'password=<password value>' \
--data-urlencode 'scope=openid'

The response from this API call is shown below. This is an access token response, however there are indicators that this is not a fully authorized token and an MFA step up is required. This is due to evaluation and enforcement of the access policy. The scope = mfa_challenge informs the application that the access_token is not fully authorized and that the user must complete an MFA flow using one of the allowedFactors. At this stage the access token may be used to read the users own enrolled factors. This can enable the application to display a selection list to the user including their enrolled MFA factors which they might like to use for an MFA authentication challenge.

{
    "access_token": "1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN",
    "allowedFactors": [
        "emailotp",
        "totp",
        "smsotp",
        "fido2",
        "signatures"
    ],
    "scope": "mfa_challenge",
    "grant_id": "50554ed4-2d69-44b7-a2d6-dc175fcbb6ec",
    "token_type": "Bearer",
    "expires_in": 1800
}

While not essential to the overall functioning of the USC application, it is interesting to introspect this initial access token to illustrate its restricted entitlement state. As can be seen in the introspection response below, the access token has only three IBM Security Verify API entitlements:

  • authn - permits the token bearer to perform MFA functions and read the users cloud directory data via /v2.0/Me
  • readEnrollMFAMethod - permits the token bearer to read the users enrolled MFA methods
  • readAuthenticators - permits the token bearer to read the users enrolled IBM Verify mobile authenticators
curl --location --request POST 'https://<tenant>/v1.0/endpoint/default/introspect' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Accept: application/json' \
--header 'Authorization: Basic N2ExZjA3NzQtOTgyNy00YjhiLWI4NTItNjRhNTJkNTFjMjhlOm9hcTFqa0JLU0c=' \
--data-urlencode 'token=1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN'

Response:

{
    "entitlements": [
        "authn",
        "readEnrollMFAMethod",
        "readAuthenticators"
    ],
    "at_hash": "c9LW3JYOnvjs-EfePXxAFw",
    "ext": {
        "tenantId": "<tenant>"
    },
    "sub": "6070004YSH",
    "policy_id": "529160",
    "amr": [
        "password"
    ],
    "uniqueSecurityName": "6070004YSH",
    "iss": "https://<tenant>/oidc/endpoint/default",
    "active": true,
    "token_type": "Bearer",
    "client_id": "7a1f0774-9827-4b8b-b852-64a52d51c28e",
    "aud": "7a1f0774-9827-4b8b-b852-64a52d51c28e",
    "grant_type": "resource_owner",
    "restrictEntitlements": true,
    "scope": "mfa_challenge",
    "grant_id": "50554ed4-2d69-44b7-a2d6-dc175fcbb6ec",
    "category": "application",
    "exp": 1623407672,
    "app_id": "4605379946084934998",
    "iat": 1623405872
}

Display an MFA selection challenge to the user

At this stage, the USC application needs to drive the user through an MFA challenge. A typical approach here might use the present access token to

  1. Obtain a list of the users available enrolled factors. If there are any and they satisfy the requirements of the allowedFactors list from the previous response, the USC might include these in a selection prompt for the user to select.
  2. Read the users account data from /v2.0/Me to obtain their email address. If the email address is set, then the MFA selection list might also include transient email OTP as an option on the MFA selection prompt.

Here is an example request and response to obtain the users enrolled factors.

curl --location --request GET 'https://<tenant>.com/v2.0/factors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer 1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN'

Response:

{
    "factors": [
        {
            "id": "59aeb30c-02b3-4602-bf70-c8005b9f8cde",
            "userId": "6070004YSH",
            "type": "smsotp",
            "created": "2021-06-11T08:13:34.732Z",
            "updated": "2021-06-11T08:13:58.405Z",
            "attempted": "2021-06-11T08:18:37.246Z",
            "enabled": true,
            "validated": true,
            "attributes": {
                "phoneNumber": "+610419673026"
            }
        }
    ],
    "count": 200,
    "limit": 200,
    "page": 1,
    "total": 1
}

Here is an example request and response to obtain the users email address from their cloud directory account data:

curl --location --request GET 'https://<tenant>/v2.0/Me' \
--header 'Accept: application/scim+json' \
--header 'Authorization: Bearer 1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN'

Response:

{
    "emails": [
        {
            "type": "work",
            "value": "[email protected]"
        }
    ],
    "meta": {
        "created": "2021-05-10T12:06:57Z",
        "location": "https://<tenant>/v2.0/Users/6070004YSH",
        "lastModified": "2021-05-12T09:45:02Z",
        "resourceType": "User"
    },
    "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User",
        "urn:ietf:params:scim:schemas:extension:ibm:2.0:User"
    ],
    "name": {
        "formatted": "Jessica Breton",
        "familyName": "Breton",
        "givenName": "Jessica"
    },
    "urn:ietf:params:scim:schemas:extension:ibm:2.0:User": {
        "lastLogin": "2021-05-12T09:45:02Z",
        "lastLoginRealm": "cloudIdentityRealm",
        "userCategory": "regular",
        "twoFactorAuthentication": false,
        "realm": "cloudIdentityRealm",
        "pwdChangedTime": "2021-05-10T12:06:57Z",
        "lastLoginType": "user_password"
    },
    "externalId": "[email protected]",
    "active": true,
    "id": "6070004YSH",
    "userName": "jessica",
    "phoneNumbers": [
        {
            "type": "work",
            "value": "9999999"
        }
    ]
}

Perform an enrolled SMS OTP for MFA

For the sake of demonstration this article will proceed here as though the application automatically selected the users enrolled sms OTP factor in order to satisfy the MFA requirements for the USC access policy. The selection is automatic because the user has only one enrolled factor from on boarding and this USC application prefers enrolled factors. An example request and response is shown below that initiates the SMS OTP delivery. Note the value 59aeb30c-02b3-4602-bf70-c8005b9f8cde in the URL of the example is the id of the users enrolled SMS OTP factor.

curl --location --request POST 'https://<tenant>/v2.0/factors/smsotp/59aeb30c-02b3-4602-bf70-c8005b9f8cde/verifications' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer 1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN' 
--data-raw '{
  "correlation": "4445"
}'

Response

{
    "id": "673ce1f9-0b0a-473d-b5e5-3bd4ddbe1cb0",
    "userId": "6070004YSH",
    "type": "smsotp",
    "created": "2021-06-11T10:25:30.539Z",
    "updated": "2021-06-11T10:25:30.539Z",
    "expiry": "2021-06-11T10:30:30.539Z",
    "state": "PENDING",
    "correlation": "4445",
    "phoneNumber": "999999",
    "attempts": 0,
    "retries": 4
}

The SMS OTP transaction has now been initiated. Shortly after, the end user will receive an SMS similar to that shown below. The SMS contains the OTP. The USC application should by now display an OTP entry prompt to allow the end user to enter the OTP contained in the SMS.

SMS OTP messageSMS OTP message

SMS OTP message

The OTP can be validated by IBM Security Verify as shown in the curl example below. A few noteworthy aspects here:

  • The id from the previous response payload is appended to SMS OTP verification URL.
  • returnJwt=true URL parameter is set. This indicates that the USC application wishes to receive a signed JWT that can subsequently be presented and exchanged for a fully authorized access token.
curl --location --request POST 'https://<tenant>/v2.0/factors/smsotp/59aeb30c-02b3-4602-bf70-c8005b9f8cde/verifications/673ce1f9-0b0a-473d-b5e5-3bd4ddbe1cb0?returnJwt=true' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer 1d7xN3ADokjxYl5tlGkQrOWriAJZ7SDRjVn8DjkN'
--data-raw '{
  "otp": "858676"
}'

Response

{
    "assertion": "eyJhbGciOiJSUzI1NiIsImtpZCI6InNlcnZlciJ9.eyJzdWIiOiI..."
}

The response payload above includes a signed JWT. The decoded JWT is shown below. This JWT asserts that an SMS OTP MFA has been successfully completed by the sub claim indicated in the JWT. The amr asserts that the user has successfully completed password and SMS OTP authentications within the context of the token grant indicated by grant_id. This basically satisfies the MFA per session rule of the governing access policy.

{
  "sub": "6070004YSH",
  "jti": "7007c7f8-4fd5-45ff-a89f-1e92bb8b1105",
  "iat": 1623407800,
  "exp": 1623408100,
  "tenantId": "<tenant>",
  "iss": "https://<tenant>/v2.0/factors",
  "aud": [
    "7a1f0774-9827-4b8b-b852-64a52d51c28e",
    "https://<tenant>/v1.0/endpoint/default/token"
  ],
  "factor": "smsotp",
  "amr": [
    "smsotp",
    "password"
  ],
  "grant_id": "1cc2fa7e-7643-4b6f-bc08-0c8713d7de0b",
  "sub_type": "uid"
}

Exchange MFA JWT for Fully Entitled Access Token

The JWT from the previous SMS OTP verification response payload can now be exchanged for a fully entitled access token using the jwt-bearer grant flow. The IBM Security Verify OIDC authorization server however will not handle this as new token grant. This will be handled within the context of the present grant_id.

curl --location --request POST 'https://<tenant>/v1.0/endpoint/default/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Accept: application/json' \
--header 'Authorization: Basic N2ExZjA3NzQtOTgyNy00YjhiLWI4NTItNjRhNTJkNTFjMjhlOm9hcTFqa0JLU0c=' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
--data-urlencode 'assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6InNlcnZlciJ9.eyJzdWIiOiI...' \
--data-urlencode 'scope=openid'

The response to the jwt-bearer token exchange is show below. This response includes a new access token value and this token is now fully authorized. The attributes within this payload are typical for OIDC token response and the USC application and its user have now completed the MFA requirements of the governing access policy.

{
    "access_token": "cw1jugH8WlwjHPQZBIYwnH4hap3UtOFHHFFKcG99",
    "scope": "openid",
    "grant_id": "1cc2fa7e-7643-4b6f-bc08-0c8713d7de0b",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJnaXZlbl9uYW1...",
    "token_type": "Bearer",
    "expires_in": 7200
}

The introspection data of this access token is shown below:

{
    "entitlements": [
        "authn",
        "manageAuthenticators",
        "manageEnrollMFAMethod"
    ],
    "at_hash": "SXEdcqh1IjQJQvIt7_r6TA",
    "ext": {
        "tenantId": "<tenant>"
    },
    "sub": "6070004YSH",
    "realmName": "cloudIdentityRealm",
    "amr": [
        "smsotp",
        "password"
    ],
    "uniqueSecurityName": "6070004YSH",
    "iss": "https://<tenant>/oidc/endpoint/default",
    "active": true,
    "preferred_username": "jessica",
    "token_type": "Bearer",
    "client_id": "7a1f0774-9827-4b8b-b852-64a52d51c28e",
    "aud": "7a1f0774-9827-4b8b-b852-64a52d51c28e",
    "acr": "urn:ibm:security:policy:id:529160 urn:ibm:security:acr:2fa",
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "restrictEntitlements": true,
    "scope": "openid",
    "grant_id": "1cc2fa7e-7643-4b6f-bc08-0c8713d7de0b",
    "userType": "regular",
    "category": "application",
    "exp": 1623415081,
    "app_id": "4605379946084934998",
    "iat": 1623407881
}

Perform USC MFA Enrollment Functions

The USC application can now enable users to perform MFA enrollment functions. An example TOTP enrollment request is show below.

curl --location --request POST 'https://<tenant>/v2.0/factors/totp' \
--header 'Content-Type: application/json' \
--header 'Accept: image/png' \
--header 'Authorization: Bearer cw1jugH8WlwjHPQZBIYwnH4hap3UtOFHHFFKcG99' \
--data-raw '{
  "enabled": true,
  "accountName": "jessica"
}'

The response is a QR Code that can be scanned by IBM Security Verify mobile authenticator.

TOTP enrollment QR codeTOTP enrollment QR code

TOTP enrollment QR code

Conclusion

This article has described how some of the key features of IBM Security Verify can be used to provided a secure, minimally authorized custom USC application. The article described how to configure OIDC applications with restricted API security entitlements. Access policy enabled the application to drive the user through an MFA step up flow so that a high level of end user identity assurance was achieved prior to allowing the user to modify the state of their MFA enrollments.


Did this page help you?