OpenID Connect (OIDC)-based MFA as a Service - BETA
- Set up at least one MFA factor on your Okta OrgThe Okta container that represents a real-world organization..
- A factor enrollment policy
- Email firstname.lastname@example.org to enable beta FF MFA_ATTESTATION for your okta org.
Enable IFrame embedding:
- From the adminAn abbreviation of administrator. This is the individual(s) who have access to the Okta Administrator Dashboard. They control the provisioning and deprovisioning of end users, the assigning of apps, the resetting of passwords, and the overall end user experience. Only administrators have the Administration button on the upper right side of the My Applications page. dashboard, navigate to Settings -> customization
- Scroll down to the IFrame Embedding section and click Edit.
- Check Allow IFrame embedding, then click Save.
Follow the steps below to setup an OIDC application in Okta and provide the artifacts (Okta org URL, clientEssentially, a client is anything that talks to the Okta service. Within the traditional client-server model, Okta is the server. The client might be an agent, an Okta mobile app, or a browser plugin. _id, client_secret) to your application.
- Navigate to Applications > Applications.
- Click Add Application.
- Click Create New AppAn abbreviation of application. Essentially, it is a web-based site used to perform any number of specific tasks, and requires authentication from end users by signing in.:
- Platform: Select Web.
- Click Sign On Method: Select OIDC Connect.
Provide an Application name and define the list of valid Login redirect URIs.
The application (RP) must request a redirect_uri from this list of URIs.
Note: Private-Use URI Scheme Redirection (com.example.app) is supported. See RFC8252 for best practices on receiving responses in native/desktop apps.
Modify the Allowed grant types to include Allow ID Token with implicit grant type.
Define a Sign On Policy requiring MFA.
By default the Application Username will be the same as the Okta user's login attribute (user.login). The value of theApplication Username must match the value that will be sent in the login_hint claim later.
Using the Profile Editor
You can use the Profile Editor and Okta Expression Language (EL) to meet your more advanced needs. For more information, see the Configure Username Override section in Manage User Profiles.
Ensure that the desired users or groupsGroups allow you to organize your end users and the apps they can access. Assigning apps to large sets of end users is made easier with groups. are assigned to the newly created application. For additional details refer to the Assign Applications sections of The Applications Page.
From the General tab of the application, navigate to the Client Credentials and retrieve the Client ID and Client secret:
Configure Your Application
To prompt for MFA Attestation, you must make an OIDC authorize request using a signed request object with the acr_values claim set to urn:okta:app:mfa:attestation. This is a JWT signed with the client_secret passed into the authorization endpoint as the request parameter.
This request ignores the current session and can be used even if another user is currently logged in.
The JWT can easily be created using a JWT library or on online JWT building tool and must follow these rules:
- idpAn acronym for Identity Provider. It is a service that manages end user accounts analogous to user directories such as LDAP and Active Directory, and can send SAML responses to SPs to authenticate end users. Within this scenario, the IdP is Okta. cannot be used
- login_hint must be supplied and match the AppUser username associated with the OIDC app
- scopeA scope is an indication by the client that it wants to access some resource. must be just openid
- acr_values must be urn:okta:app:mfa:attestation
- response_type must be just id_token
- MFA Attestations are only supported on the Org Authorization Server
Use the following resources to provide additional context and guidance:
- Okta specific OIDC documentation can be found here:
- Online JWT Encode and Decode tools with tips can be found here:
The calling application (RP) will require the following information about your Okta org and OIDC application
- $base_url (for example: https://mattegantest.oktapreview.com)
- $client_id (for example: 0oaevei26hCJ198vv0h7)
- $client_secret (for example: aaGSo9SSspR1MqxHUaz6Ypgq7qaAc9MnMMv_eVYP)
**Client_ID & Clent_Secret can be found under the General tab of your OIDC app. **
Set nonce = A secure random string (sufficiently long)
Store the nonce on the app backend (i.e. the value should not be available to user in any form or shape)
Generate and sign a JWT Request:
- Requests should be signed using HS256 with the client_secret
- iat (issued at time) should be used
- exp (expiration time) with a lifetime that accommodates for reasonable clock skew and round trip should be used
Example request JWT created by app requesting MFA from Okta:
Sample request JWT:
Refer to RFC8252 for best practices on redirect_uri usage with native app and other non-web flows.
Sample signed and encoded request JWT:
Direct the UserAgent to the /oauth2/v1/authorize endpoint providing the signed JWT as the request
GET $base_url/oauth2/v1/authorize?request=<signed JWT request>
- If you are using a browser to navigate to the above URL then it is recommended to have the response_mode set to "form_post"
- If post message is used to post the signed id token back then the parent frame will receive the id token as a posted message. If "form_post" was used the id token will be posted to the redirect URI specified on the app. The signed token will be received after a user successfully completes authentication/mfa validation on Okta.
- The application backend should take the id token and validate it using the keys got from - https://org.okta.com/oauth2/v1/keys and use the kid specified in the response jwt header as the index into the response of "/oauth2/v1/keys". And finally it also should make sure that the nonce on the signed token is same as what it has (stored in initial steps above) for the authentication transaction.
The user will be presented with an Okta MFA challenge, this will eventually include factor enrollment driven by enrollment policies in Okta.
- Factor selection
- Multiple factor support
- Multiple factor provider
- Defaults to last used
Challenge resp flow varies by factor type and provider
Factor Enrollment and Recovery (FEaR)
The problem you didn’t even know you had
Okta provides extensible policies to control this behavior
Once the user has successfully satisfied the MFA challenge the UserAgent will be provided an id_token to deliver to the application (RP).
At this point in the flow the UserAgent (browser) is sent to the requested redirect_uri with the id_token in the requested response_mode (fragment shown).
If a state claim was included in the request JWT the value will be included in the response. The requested response_mode will dictate how, show below is an example where the response mode is fragment.
Sample redirect, id_token and state
To ensure the validity of the response received from the UserAgent the application (RP) should validate the response using one of the following methods.
Ensure that the value(s) returned in the amr satisfy the needs of your request. This is an attestation of what authentication methods Okta used. A list of valid responses and their meaning can be found here (https://developer.okta.com/docs/api/resources/sessions#amr-object)
An empty amr is an indication that the policy configured created a condition where no MFA was performed
For more detailed information please refer to Validating ID Tokens.
The high-level overview of validating an ID token looks like this:
- Retrieve and parse your Okta JSON Web Keys (JWK)
- These should be checked periodically and cached by your application
- Decode the ID token, which is in JSON Web Token format
- Verify the signature used to sign the ID token
- The JWT header will indicate the Key Identifier (kid) and algo used (‘rs256’)
- Verify the claims found inside the ID token
Alternatively, you can also validate an ID Token using the Token Introspection endpoint. This endpoint takes your id_token as a URL query (token=<id_token_jwt>) and returns back a JSON response with a boolean active property. If active is true then further information about the token is returned as well.
This incurs a network request which is slower to do verification, but can be used when you want to guarantee that the access token hasn’t been revoked.
References and Notes
- Okta specific OIDC documentation can be found here
- Online JWT Encode and Decode tools with tips can be found here: https://www.jsonwebtoken.io/
Nonce implementation notes: http://openid.net/specs/openid-connect-core-1_0.html#NonceNotes
The requesting application (RP) should bind the nonce to the "session" its own side (by generating the nonce from a hash of the local "session id" if possible). It should then verify that the nonce which came back inside the signed ID token matches the one it sent in on the authorize request.
Request exp should allow sufficient time for clock skew and latencyTop