Repository navigation
feat(core): accept recent OIDC authentication context in the account API - #9771
Open
wangsijie wants to merge 3 commits into
Conversation
wangsijie
force-pushed
the
wangsijie-log-14124-accept-recent-oidc-authentication-context-in-account-api-and
branch
from
October 16, 2026 07:59
c50bd98 to
2270221
Compare
wangsijie
changed the base branch from
master
to
wangsijie-swagger-dev-feature-pruning
October 16, 2026 07:59
This was referenced Oct 16, 2026
`koaOidcAuth` derives `identityVerified` from the access token's authentication context as well as the legacy `logto-verification-id` header: a first-party token whose `acr` satisfies `urn:logto:acr:1fa` and whose `auth_time` is at most 600 seconds old authorizes sensitive Account API operations without a separate verification record. The branch fails closed for missing, malformed, stale, future, or third-party values, never reads `iat`, and is guarded by `isDevFeaturesEnabled`; the legacy branch is unchanged. A sensitive route that lacks recent authentication now answers with the RFC 9470 challenge next to the existing 401 body, built by one shared helper and emitted only for first-party callers, which are the only ones a step-up can help. The account reads that need recent authentication (backup codes, sessions, grants, and trusted devices) additionally require a first-party application, so a third-party token from a fresh sign-in can no longer read them. Amp-Thread-ID: https://ampcode.com/threads/T-01a14383-fded-744a-b90a-56f48926c865
…tication context The shared profile helper imported the step-up helper, which pulls `@silverhand/slonik` (a dev dependency, so it is bundled) into every test entry that imports it: the console and experience suites then failed to load with a dynamic `require` error. The helper now signs in through the mock social connector with its own connector setup, and removes the identity it linked when the user had none, so it leaves the account as it was found. Also sign in before binding MFA factors, whose verification a sign-in then requires; enable trusted devices in `enableAllAccountCenterFields`; request `profile` for the third-party read case, which the SDK always asks for; and read the challenge response without the client throwing on the 401. Amp-Thread-ID: https://ampcode.com/threads/T-01a142a9-f6bd-706b-a70d-f77ec3058cc0
The positive OIDC branch and the RFC 9470 challenge only exist with the feature enabled, so those two cases use `devFeatureTest`. The legacy verification record case still runs in both modes. Amp-Thread-ID: https://ampcode.com/threads/T-01a142a9-f6bd-706b-a70d-f77ec3058cc0
wangsijie
force-pushed
the
wangsijie-log-14124-accept-recent-oidc-authentication-context-in-account-api-and
branch
from
October 16, 2026 08:57
2270221 to
e4a5a66
Compare
wangsijie
changed the base branch from
wangsijie-swagger-dev-feature-pruning
to
wangsijie-share-identity-verified-assertion
October 16, 2026 08:57
3 tasks done
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One vertical slice for M6: the Account API derives
identityVerifiedfrom the access token's authentication context, keeps the legacylogto-verification-idpath working, and answers a missing or stale proof with an RFC 9470 challenge.koaOidcAuth(packages/core/src/middleware/koa-auth/):identityVerifiedis nowoidcVerified || legacyVerified. The OIDC branch requires a first-party caller, anacrthat satisfiesurn:logto:acr:1fa, and anauth_timeno older than 600 seconds, and fails closed on a missing, malformed, stale, future, third-party, or CIMD client value. Token issuance time (iat) is never used, and the legacy record's ownership, expiry, verification type, and template checks are untouched.authentication-context.tsholds the policy in one place: the required ACR, the maximum authentication age, the strict parse of the token'sacr/auth_time, and the challenge builder that escapes quoted-strings.packages/core/src/routes/account/): the sharedassertIdentityVerifiedhelper emits the challenge for a first-party caller only, since a step-up cannot help a third-party application. The failure keeps the 401 status and theverification_record.permission_deniedbody, check order is unchanged so third-party error codes stay as they are, and the initial-password exception is unchanged.WWW-Authenticateheader itself is not described in the supplement yet — its documentation lands with the release that makes the challenge unconditional, so the served document never promises a header an installation does not send.Resolves LOG-14124.
What moved out of this PR
The original PR also carried a released-behavior fix and an extraction. They are separate now, so each can be reviewed and shipped on its own:
assertIdentityVerifiedassertion.Testing
Unit tests, integration tests.
1fa/mfa, stale, future, missing, malformed, and non-Logtoacr, third-party and CIMD clients, legacy record path), for the challenge header format and escaping, and for challenge emission from a first-party caller only.oidc-authentication-context.test.tsfor the fresh-context and challenge paths, while the legacy-path negative cases sign in through the mock social connector, which recordsamr=["fed"]and noacr. Left to CI.Checklist