Step-up authorization
Note: This is a [Beta] feature, to request access to use this feature, please reach out to our support to enable it for your account.
Backgroundโ
Step up authorization is the process of converting a user's auth from a base level to an elevated or privileged state. This is usually achieved by utilizing the user's preconfigured two factor authentication methods.
The result should be that the user is now able to access the more restricted resources on an account. This can be used to safeguard critical aspects of an account without inconveniencing the user by forcing 2FA from the beginning.
However this is where trouble lies. And unfortunately, solutions are of the form:
- Forcing the user to do a full login again, using a different--method, tenant, connection, user identity pool--which has a 2FA enabled
- Storing the updated credential and losing the previous login
- User is stuck in elevated state
- Unable to segregate and explicitly identity which resources should be restricted
This is called step-up authentication. This is actually a bad anti-pattern. The user's identity hasn't changed, and usually you aren't concerned with user identity here.
(There are some cases where we might require multiple forms of user identity that are desired for trust or user delegation, but all of these provide a better user experience by having remembered 2FA, location/ip address based validation, and user agent/browser token persistence during the initial login. All these aspects would be in the authentication domain and authentication should stop at user login.)Most of the time however, what we really want to do, is secure access to specific resources for the users benefit. Since we are talking about resource access, the appropriate term is step-up authorization and not step-up authentication.
This is an authorization and access problem, not an identity one.โ
So using login or identity tools to do this is a mistake. It's a different domain and so we should use the tools in the appropriate domain.
To do step-up authorization, your CIAM or authorization provider must support protected resource configuration to allow specifying when a user needs a step-up challenge. This also has the unique advantage of isolating security spheres and keeping the privileged access limited to the service/product/location that requested it, rather than applying it to the user identity across the board.
In the case with user token changes, (i.e. the use of step-up authentication with re-login) you can't restrict which resources need access. Further there is no way to reduce the access again without logging the user out or hacking the integration with the user's identity provider to store multiple tokens, assuming the identity provider enables this at all. And thus having to store multiple tokens in every user client session, which becomes more of a problem when there are multiple apps involved or multiple user agents.
Another way to look at the issue here is that, the user agent domain should never have to care about step-up access, the service API is the only one that should know this is required, and ask for it at the right time. But having step-up required, supported, and a first-class requirement of user-agents such as browsers incorrectly couples step-up flows with the UI the user interacts with. This fragments the implementation and segregates the understanding of the security features from where they are needed to where they should be opaque. Security is needed in the service, but the setup and management is forced into the UI. This is clearly incorrect. We want to have the knowledge of the security implementation to be directly aligned with the location where the step-up is requested.
For the purposes of this implementation, we'll walk through the architecture and integration with Authress to see how to easily implement step-up auth.
Step-Up Authorization configurationโ
Authress breaks this down into a couple of different parts, we'll go over each one of them here.
1. Specify the resource is protectedโ
The first step is to mark access to the specific resource as protected by step-up authorization. There are multiple ways to do this in practice, the preferred way is to specify in the access record that permission to access the resource should only happen with elevated token permissions.
Enabling this feature causes authorization checks to fail unless the user and token requesting the resource has been stepped-up.
2. Complete the normal login flowโ
Users will navigate through your login as normal. As part of their account configuration, make sure to capture any mechanism you would like to use for the step-up flow. You're probably already capturing their email or phone-number, however any available mechanism could be valid. It could even be the case to use Authress multi-signature request approval for this. Authress supports Access Requests which generates a long running process to approve that request before granting the user access. In some cases, multiple entities must be involved in the step up request, and Authress provides a way to support it.
3. Make the authorization requestโ
As usual, the user navigates through the resources in your platform. When they attempt to perform actions on your resources, you make the appropriate authorization checks.
import { AuthressClient } from '@authress/sdk';
const authressClient = new AuthressClient()
[GET('/v1/resources/{resourceId}')]
function getResource(request) {
try {
await authressClient.userPermissions.authorizeUser(userId, `resources/${resourceId}`, 'READ');
// Application route code
return OK;
} catch (error) {
if (error.code === 'StepUpAuthorizationRequired') {
await issueStepUpChallenge(error.stepUpChallengeToken);
return Forbidden;
}
return ServiceUnavailable;
}
}
For language specific implementations of authorization checks, see the available Authress SDKs.
4. Perform the step-upโ
As part of the response from Authress on required step-up access includes the details to enforce the step-up challenge. Authress has the capability to generate a challenge code for future verification and verify a returning code for the user, this prevents just any valid client from approving the step-up. The recommended approach is:
- On a this failure, inspect the response, and check if a step-up challenge is necessary.
- In the case where a step up is required, issue the step-up challenge to the user, have the user complete their flow.
Since this is all in the user authorization domain, the user doesn't need to sign in again and no changes to the user identity nor delegation to an identity provider is necessary. Issue the challenge and wait to hear back from the user.
5. Record to the step-up challenge resultโ
In the case that the user successfully completes your step-up challenge result, the question becomes
How does the app link this elevated access to the existing user identity?
Since we want to restrict elevated permissions to authorization requests utilizing the user's access token only, make a request to Authress' user identity endpoint for the access token.
(This should be trivially obvious. If the user is logged in with more than one device, we only want one access token to be granted elevated permissions. This prevents accidentally granting all access tokens ever issued, that might still be active, elevated access. And additionally, the access token given granted step-up is fully controlled by your app/service/platform. This means the user can complete the challenge on their mobile device and elevated access will automatically happen in the browser session without ever needing to perform extra actions in either.)
To record the step-up authorization challenge success for an access token, make the relevant call to the Authress API:
import { AuthressClient } from '@authress/sdk';
const authressClient = new AuthressClient()
function handleChallengeResult(stepUpChallengeToken) {
// Set the user's token as part of the request
const authorizationToken = request.headers.get('authorization');
authressClient.setToken(authorizationToken);
// Use the stepUpChallengeToken from the error response to upgrade the state
await authressClient.userPermissions.stepUpAuthorization(stepUpChallengeToken);
return OK;
}
6. Continue with the user resource actionโ
Once the step up challenge has been completed by the user, verified by the app service or platform using one of the user's registered multifactor devices, The user can be directed to make the same resource requests again. These resource requests will be successful, and the user can perform their desired actions.
Once the actions have been completed. The app can optionally remove the step up authorization, by issuing another call to Authress, and revoking the permission. This also makes for a great flow in high-risk environments, where the user might not trust their device. This these situations, they can request that the step-up be always performed, and their associated access records can be modified to require that the user's step up happens before access to the protected resources is given.