Add nonce support to createAuthUrl - #60
Merged
Merged
Conversation
The OIDC Auth API accepts an optional `nonce` in the authorization request JWT and echoes it back as a claim in the id_token. exchangeAuthorizationCodeFor2FAResult already accepted a nonce to verify, but there was no way to send one, so the feature was unreachable. Add an options object to createAuthUrl carrying the nonce, plus a generateNonce() helper mirroring generateState(). Length bounds follow the published API (16-1024) rather than the stricter state floor of 22. An absent nonce omits the claim entirely; an explicit empty string is rejected rather than silently dropped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Generate a nonce alongside the state, store it in the session, and pass it to both createAuthUrl and exchangeAuthorizationCodeFor2FAResult so the example demonstrates the full round trip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
scweber-cisco
marked this pull request as ready for review
September 4, 2026 20:34
Welcome to Codecov 🎉Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests. Thanks for integrating Codecov - We've got you covered ☂️ |
AaronAtDuo
reviewed
Sep 8, 2026
AaronAtDuo
approved these changes
Sep 8, 2026
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
The OIDC Auth API accepts an optional
noncein the authorization request JWT and echoes it back as a claim in theid_token.exchangeAuthorizationCodeFor2FAResultalready accepted anonceargument to verify against, but there was no way to send one — so the feature was unreachable.This adds the missing half.
Changes
createAuthUrl(username, state, options?)takes a newAuthUrlOptionsobject carryingnonce. The options object (rather than a positional arg) leaves one extension point for the other optional authorize params the API documents but the SDK doesn't yet support —dest_app_name,dest_app_id,display_username.generateNonce()helper, mirroringgenerateState().MIN_NONCE_LENGTH = 16,MAX_NONCE_LENGTH = 1024— rather than the stricter floor of 22 the SDK applies tostate. Out-of-range values throwDuoException(DUO_NONCE_ERROR).nonceomits the claim entirely; an explicit empty string is rejected rather than silently dropped.Additive and non-breaking — existing two-argument
createAuthUrlcallers are unaffected.Testing
8 new unit tests (58 total, all green) covering
generateNoncelength and uniqueness, claim present/absent, the three rejection cases, and a fullcreateAuthUrl→id_token→ verification round trip.Also exercised end-to-end against a live Duo test tenant through the example app:
auth_result: allow, nonce echoed back intactDuoException: The nonce is invalidThe negative case is the useful one: Duo completed 2FA and issued a valid
duo_codeand well-formedid_token; the SDK rejected it purely on the nonce mismatch.Note for reviewers
While testing, the live
id_tokencame back with several fields absent fromTokenResponsePayload—amrandtrusted_endpoint_status, plus three the public docs don't mention at all:passport_assessment,access_device.management_agents, andauth_device.type/serial. Not addressed here; happy to follow up in a separate PR.🤖 Generated with Claude Code