Let's talk about the step up auth RFC
A new CIAM related RFC was released in Sep 2023. It builds on the OIDC specification, but covers step up authentication in the OAuth context (with tokens and an authorization server and all that jazz). I wanted to dig into the RFC.
What is step up auth?
Have you ever been prompted to log in when taking an action in a web app, even though you already recently authenticated? Perhaps you were about to take a high value action, such as transferring money, and a message popped up saying something like “please authenticate again”.
This is known as a “step up” because you are providing additional proof that you are who you say you are. At a high level, a step up works like this:
a user is authenticated
they take an action determined by the application to require additional authentication proof
the user is prompted to authenticate again
when the user successfully authenticates, the action is completed
The specific authentication mechanism is application specific. You mght be prompted for an additional factor, unique information, or to enter your password.
Similarly, the events which trigger step up auth are tied to an application. The right place to require step up auth differs between a bank, a recipe site and an ecommerce store.
Why might you want your users to ‘step up’
A step up request is is often sent in risky situations, such as the aforementioned money transfer. Other areas of functionality which require certainty about the user requesting them include:
changing or adding login credentials
administrative actions
interactions after a session has been stale for a while
modifications with real world consequences, such as changing a shipping address
destructive actions, especially if it can’t be undone
Now you know what step up auth is and when you might want to trigger it. Next, let’s look at what the RFC says.
What does the RFC outline?
Warning, here comes the jargon! It is an IETF RFC, after all.
If you need a refresher, read RFC 6749 or these cliff notes.
A client is an application trying to gain access to protected resources. It’s doing so on behalf of a user or software application.
A resource server holds protected resources. It often serves them up as an API, but that’s not required.
An authorization server issues tokens after authenticating a user or software application.
Tokens are timebound credentials which the resource server can use to determine if a request is allowed.
The OAuth 2.0 Step Up Authentication Challenge Protocol RFC wisely refrains from diving into business logic. Instead, it defines a method for a resource server to, when examining a token, communicate that the token is not invalid per-se, but that a higher level of access is needed than what the token provides.
Elevated access conditions
There are two forms of access conditions which a resource server might request which are outlined in the RFC.
The first is time based. From the RFC, a resource server can specify “the allowable elapsed time in seconds since the last active authentication event associated with the access token”. Basically, the token presented is too stale for the resource server’s tastes. This is represented as a max_age
value in the RFC.
The second is authentication based. Basically, a certain authentication context. For instance, a resource server may be presented with an access token that was generated through by a one-factor authentication such as a password. The resource server may require a two-factor authentication. This is represented as an acr_values
parameter in the RFC.
The step up auth process
So, if the resource server needs to know the user has authenticated within a certain time or with a certain mechanism, how does it actually request that?
First, the client has to request the protected resource, presenting a token.
The resource server responds with an error message. This error message is fully defined in the RFC, but includes a status code (401
), an error field with the value insufficient_user_authentication
and an auth-param value indicating whether the token is stale, another form of authentication is required, or both.
The client parses the response from the error message and constructs a request to the authorization server for the elevated access level.
The authorization server then re-authenticates the client. If it cannot (perhaps because the authentication mechanism requested by the resource server is not supported by the authorization server) then it fails the request.
If the authentication succeeds, the token should have an updated auth_time
and acr
claims, where the former is the time of authentication and the latter is the method.
That token is then presented to the resource server by the client. At this point, the resource server is satisfied and the client can access the resource it was seeking.
What are valid acr_values?
It is pretty clear to me the value and functionality of the stale token flow. A resource server about to allow a privileged action may want a recent authentication event. The value of the parameter is the number of seconds since the last authentication event. Pretty straightforward.
Requiring authentication assurance makes sense to me as well. But unlike the stale token error, the value of the auth-param returned is unclear to me. The specification uses the example value myACR
which is not very illustrative.
What are valid acr_values
for a resource server to return? This post from Stackoverflow talks about how acr_values
in the OIDC context are shared agreements between the resource server and the authorization server.
You either need to decide on these if they are configurable and you control both servers, or read the authorization server documentation and make sure your resource server returns an appropriate value. Okta, for example, has predefined acr_values
.
But are there any standard acr_values
parameter values?
Taking a step back, in RFC 8176, it’s clear that acr_values
don’t relate to specific authentication methods such as an SMS MFA or username/password. Instead,
The "acr" (Authentication Context Class Reference) claim and "acr_values" request parameter are related to the "amr" (Authentication Methods References) claim, but with important differences. An Authentication Context Class specifies a set of business rules that authentications are being requested to satisfy. These rules can often be satisfied by using a number of different specific authentication methods, either singly or in combination. Interactions using "acr_values" request that the specified Authentication Context Classes be used and that the result should contain an "acr" claim saying which Authentication Context Class was satisfied. The "acr" claim in the reply states that the business rules for the class were satisfied -- not how they were satisfied.
Password or webauthn authentication are methods, not business rules. Here is an IANA list of methods, just for grins, though.
The IETF mailing list didn’t have any examples. However, using google I found a few standard acr_values
examples.
The OpenID Connect Extended Authentication Profile specifies two values:
phr
andphrh
. The former indicates phishing resistant mechanisms and the latter indicates phisch resistant mechanisms that use hardware.The OpenID Connect MODRNA Authentication Profile specifies two values:
mod-pr
andmod-mf
. The former indicates posession of a device containing a secret key and the latter indicates there was a pin or device unlock.There are SAML based levels of assurances.
In short, there’s not a lot out there for acr_values
. To use this, either consult your authorization server documentation or set up your own.
Thanks to the authors
Finally, Vittorio Bertocci was one of the co-authors of this RFC.
He has life-threatening health problems and wrote a touching post about the RFC and his co-author, Bruce Campbell.
Thank you, Vittorio, for all your knowledge sharing and your efforts to make the identity world better for everyone.
Dan