You can use the linked APIs, and that’s the path most people find first. The step-up flow in the API docs works, but it means your app owns the challenge: start it, collect the code, handle the result. That’s a lot of surface area for what is basically “make the user log in again because they are about to do a sensitive thing.”

There’s another way that’s a little different than what people might expect, and it uses what you probably already have built. Since version 1.60 the authorize endpoint supports the standard OIDC prompt and max_age parameters.

When your app hits a sensitive action, it doesn’t call any specific APIs. Instead, it can redirect the user to /oauth2/authorize with prompt=login and/or with a max_age small enough that their existing SSO session doesn’t satisfy it. FusionAuth shows the hosted login page, the user authenticates, and you get a fresh token back. Same code you already wrote for login, plus one query parameter.

max_age=0 and prompt=login end up in roughly the same place. I’d use max_age if you want a window like “re-auth if it’s been more than five minutes,” and prompt=login if you want it every time.

A successful redirect doesn’t prove anything by itself, because your API still has to decide whether the token it’s looking at came from a recent authentication. That’s what the auth_time claim is for. It’s a reserved claim in the JWT body (it moved there in 1.60, and lambdas can’t override it), so your resource server compares it against the clock and rejects anything older than your threshold. If it’s too old, send the user back through authorize. That’s basically the max_age half of RFC 9470, just without FusionAuth issuing the WWW-Authenticate challenge for you. You’d write that 401 yourself.

Now the caveats:.

This forces a re-login, not necessarily a stronger one. If the user re-authenticates with a password and nothing else, you’ve proven recency and nothing about strength. If you need the second factor on that re-auth, you need MFA to actually fire. A static policy of Required will do it. On Enterprise, the MFA Requirement Lambda can make the decision per request. There’s no acr-style “this was step-up” claim. You get “authenticated at time T,” not “authenticated with a second factor at time T.” If your auditors need the latter, this approach won’t give it to you cleanly, and falling back to the step-up auth API is a better path. It’s a full redirect. For a banking-style “confirm this transfer” flow where bouncing the user to another page is a non-starter, the API approach is still right. This only works when you are using the hosted login pages, not the Login API.

The short version: if sensitive actions are coarse-grained (“view the billing page,” “change the email address”), try the redirect approach first. It’s less code, the hosted pages handle the UI, and you’re not maintaining a custom MFA challenge. If you need per-operation binding or proof of which factor was used, you’re back in the APIs.