<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Additional authentication assurance without using step-up MFA]]></title><description><![CDATA[<p dir="auto">I need the user to prove they’re still the user before a sensitive action. Do I really have to wire up the Two-Factor APIs to use <a href="https://fusionauth.io/docs/lifecycle/authenticate-users/multi-factor-authentication#step-up-auth" rel="nofollow ugc">step-up MFA auth</a> to do that?</p>
]]></description><link>https://fusionauth.io/community/forum/topic/3244/additional-authentication-assurance-without-using-step-up-mfa</link><generator>RSS for Node</generator><lastBuildDate>Sun, 18 Oct 2026 02:11:32 GMT</lastBuildDate><atom:link href="https://fusionauth.io/community/forum/topic/3244.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 12 Oct 2026 16:59:17 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Additional authentication assurance without using step-up MFA on Wed, 14 Oct 2026 15:01:58 GMT]]></title><description><![CDATA[<p dir="auto">You can use the linked APIs, and that’s the option most people find first. The step-up flow in the API docs works, but means your app owns the challenge. It has to start it, collect the code, and handle the result. That’s a lot for what is basically “make the user log in again because they are about to do a sensitive thing.”</p>
<p dir="auto">There’s another way that’s a little different, and it leverages login. Since version 1.60 the <code>authorize</code> endpoint supports the standard OIDC <code>prompt</code> and <code>max_age</code> parameters.</p>
<p dir="auto">When your app hits a sensitive action, don't call any specific APIs. Instead, it can redirect the user to /oauth2/authorize with <code>prompt=login</code> and/or with a <code>max_age</code> 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, with one query parameter added.</p>
<p dir="auto">Make sure you put the current page/location in the state so you can deliver the customer back to where they were. Here's a <a href="https://www.youtube.com/watch?v=-vx5rdy-mvY" rel="nofollow ugc">video on deep linking</a>.</p>
<p dir="auto">Using either <code>max_age=0</code> and <code>prompt=login</code> end up in roughly the same place. I’d use <code>max_age</code> if you want a window like “re-auth if it’s been more than five minutes,” and <code>prompt=login</code> if you want it every time.</p>
<p dir="auto">A successful redirect doesn’t prove everything. Your app still has to decide whether the token it’s looking at came from a recent authentication.</p>
<p dir="auto">That’s what the <code>auth_time</code> 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 beyond your threshold. If it’s too old, send the user back through <code>authorize</code>.</p>
<p dir="auto">That’s basically the <code>max_age</code> half of RFC 9470, just without FusionAuth issuing the <code>WWW-Authenticate</code> challenge for you. You’d write that 401 yourself.</p>
<p dir="auto">Caveats:.</p>
<ul>
<li>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 <code>Required</code> will do it. On Enterprise, the <a href="https://fusionauth.io/docs/extend/code/lambdas/mfa-requirement" rel="nofollow ugc">MFA Requirement Lambda</a> can make the decision per request.</li>
<li>There’s no <code>acr</code>-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 option.</li>
<li>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 step-up API approach is still right.</li>
<li>This only works when you are using the hosted login pages, not the Login API.</li>
</ul>
<p dir="auto">The short version: if sensitive actions are coarse-grained (“view the billing page,” “change the email address”), the redirect approach might work for you. It’s less code, the hosted pages handle the UI, and you’re not maintaining a custom MFA challenge.</p>
<p dir="auto">But if you need per-operation binding or proof of which factor was used, look at the step-up API.</p>
]]></description><link>https://fusionauth.io/community/forum/post/8825</link><guid isPermaLink="true">https://fusionauth.io/community/forum/post/8825</guid><dc:creator><![CDATA[dan]]></dc:creator><pubDate>Wed, 14 Oct 2026 15:01:58 GMT</pubDate></item></channel></rss>