Skip to content

Add nonce support to createAuthUrl - #60

Merged
AaronAtDuo merged 3 commits into
duosecurity:mainfrom
scweber-cisco:add-nonce-support
Sep 8, 2026
Merged

AaronAtDuo merged 3 commits into
duosecurity:mainfrom
scweber-cisco:add-nonce-support

Conversation

@scweber-cisco

Copy link
Copy Markdown
Contributor

Summary

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 argument 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 new AuthUrlOptions object carrying nonce. 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.
  • New generateNonce() helper, mirroring generateState().
  • Length bounds follow the published API — MIN_NONCE_LENGTH = 16, MAX_NONCE_LENGTH = 1024 — rather than the stricter floor of 22 the SDK applies to state. Out-of-range values throw DuoException(DUO_NONCE_ERROR).
  • An absent nonce omits the claim entirely; an explicit empty string is rejected rather than silently dropped.
  • The example app now generates a nonce, stores it in the session next to the state, and passes it to both calls.

Additive and non-breaking — existing two-argument createAuthUrl callers are unaffected.

Testing

8 new unit tests (58 total, all green) covering generateNonce length and uniqueness, claim present/absent, the three rejection cases, and a full createAuthUrl → id_token → verification round trip.

Also exercised end-to-end against a live Duo test tenant through the example app:

Case Result
Nonce matches Token verified, auth_result: allow, nonce echoed back intact
Nonce deliberately mismatched DuoException: The nonce is invalid

The negative case is the useful one: Duo completed 2FA and issued a valid duo_code and well-formed id_token; the SDK rejected it purely on the nonce mismatch.

Note for reviewers

While testing, the live id_token came back with several fields absent from TokenResponsePayload — amr and trusted_endpoint_status, plus three the public docs don't mention at all: passport_assessment, access_device.management_agents, and auth_device.type/serial. Not addressed here; happy to follow up in a separate PR.

🤖 Generated with Claude Code

scweber-cisco and others added 2 commits September 4, 2026 16:01
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
scweber-cisco marked this pull request as ready for review September 4, 2026 20:34
@codecov-commenter

Copy link
Copy Markdown

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 ☂️

Comment thread example/README.md Outdated
@AaronAtDuo
AaronAtDuo merged commit 4340745 into duosecurity:main Sep 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants