Skip to content

ID token validation for the API that return id token as part of Credentials and SSOCredentials#1091

Merged
NandanPrabhu merged 16 commits intodevelop/v3.0from
id_token_validation
Mar 13, 2026
Merged

ID token validation for the API that return id token as part of Credentials and SSOCredentials#1091
NandanPrabhu merged 16 commits intodevelop/v3.0from
id_token_validation

Conversation

@NandanPrabhu
Copy link
Copy Markdown
Contributor

@NandanPrabhu NandanPrabhu commented Feb 19, 2026

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

📋 Changes

Introduces opt-in, chainable ID token validation for credential-returning Authentication methods

New TokenRequestable protocol — extends Requestable and is returned by all credential-producing methods (login, codeExchange, renew, ssoExchange, and MFA verify variants). It exposes a fluent validation builder:

Auth0
    .authentication()
    .renew(withRefreshToken: refreshToken)
    .validateClaims()            // opt in
    .withLeeway(120)             // seconds; default 60
    .withNonce("abc")
    .start { result in ... }

Key design decisions:

  • Validation is off by default — calling .validateClaims() opts in; omitting it preserves existing behaviour unchanged.
  • If validation is enabled but the response contains an empty ID token, the request fails with IDTokenDecodingError.missingIDToken rather than silently succeeding.
  • parameters(), headers(), and requestValidators() preserve the concrete return type so .validateClaims() can be chained in any order.
  • All validator ValidationError types now conform to a shared IDTokenValidationError marker protocol, replacing the previous exhaustive type-check in isIDTokenValidationError.
  • Auth0MFAClient propagates dpop, logger, and auth0ClientInfo updates to its underlying Authentication instance via didSet observers.
  • withLeeway now takes seconds (consistent with withMaxAge); default is 60.

No migration required for call sites. Protocol conformances (mocks, custom Authentication implementations) must update method return types from any Requestable to any TokenRequestable for credential-returning methods.

🎯 Testing

All existing unit tests pass. New coverage added for:

  • validateClaims() with valid, invalid, and missing ID tokens
  • didSet propagation on Auth0MFAClient for dpop, logger, and auth0ClientInfo
  • DPoP assertions updated to cast to the concrete TokenRequest or Request type since dpop is not part of the Requestable/TokenRequestable protocol surface

@NandanPrabhu NandanPrabhu changed the base branch from master to develop/v3.0 February 19, 2026 05:42
@NandanPrabhu NandanPrabhu added Swift v3.0 This label depicts this feature is part of Swift 3.0 DO NOT REVIEW labels Feb 23, 2026
@NandanPrabhu NandanPrabhu force-pushed the id_token_validation branch 2 times, most recently from 17f7333 to c386dec Compare February 25, 2026 13:19
@NandanPrabhu NandanPrabhu marked this pull request as ready for review February 25, 2026 13:41
@NandanPrabhu NandanPrabhu requested a review from a team as a code owner February 25, 2026 13:41
@pmathew92 pmathew92 requested a review from Copilot February 25, 2026 15:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request moves ID token validation from a separate post-processing step to request-level response handlers for all Authentication and MFAClient APIs that return credentials. The changes ensure ID tokens are validated immediately when received, improving security and developer experience by eliminating the need for manual validation steps.

Changes:

  • Introduced IDTokenProtocol to identify credential types carrying ID tokens (Credentials and SSOCredentials)
  • Added ID token validation parameters (issuer, leeway, maxAge, nonce, organization) to all credential-returning methods in Authentication and MFAClient protocols
  • Implemented request-level validation handlers (authenticationDecodableWithIDTokenValidation and mfaVerifyDecodableWithIDTokenValidation) that validate tokens before invoking success callbacks
  • Updated CredentialsManager to accept validation parameters and skip retry logic for deterministic validation failures
  • Modified PKCE flow in OAuth2Grant to use new validation integration and improve error mapping
  • Added isIDTokenValidationError() helper to accurately identify validation errors without false positives
  • Updated GitHub Actions workflow files (note: contains incorrect Xcode version numbers)

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Auth0/IDTokenProtocol.swift New protocol defining types with ID tokens (Credentials, SSOCredentials)
Auth0/IDTokenValidator.swift Added helper function to identify specific ID token validation error types
Auth0/AuthenticationHandlers.swift New handler integrating ID token validation for Authentication API responses
Auth0/MFA/MFAHandlers.swift New handler integrating ID token validation for MFA API responses
Auth0/MFA/MFAClient.swift Updated protocol with validation parameters; added backward-compatible extension
Auth0/MFA/Auth0MFAClient.swift Implementation of validation parameter support in MFA verify methods
Auth0/OAuth2Grant.swift Refactored PKCE flow to use request-level validation with improved error mapping
Auth0/Authentication.swift Updated protocol methods with validation parameters; added backward-compatible extension
Auth0/Auth0Authentication.swift Implementation of validation parameters across all credential-returning methods
Auth0/CredentialsManager.swift Added validation parameters and logic to bypass retry for validation failures
Auth0/Request.swift Added @escaping annotation to callback closure for correctness
Auth0/Credentials.swift Minor whitespace cleanup
Auth0Tests/MFA/Auth0MFAClientTests.swift Updated tests with authentication parameter for MFA verify methods
Auth0.xcodeproj/project.pbxproj Added IDTokenProtocol.swift to build targets
App/ContentViewModel.swift Removed WEB_AUTH_PLATFORM conditional compilation directives
App/ContentView.swift Removed WEB_AUTH_PLATFORM conditional compilation directives
.github/workflows/rl-scanner.yml Updated Xcode version (contains error: "26.2" is invalid)
.github/workflows/main.yml Updated Xcode version and macOS runner (contains error: "26.2" is invalid)
Comments suppressed due to low confidence (4)

Auth0/MFA/Auth0MFAClient.swift:205

  • There's redundant error wrapping logic here. The mfaVerifyDecodableWithIDTokenValidation handler (line 74 in MFAHandlers.swift) already wraps ID token validation errors in MFAVerifyError(cause: error). Then this code checks if error.cause is an ID token validation error and wraps it again in MFAVerifyError(cause: cause), creating a double-wrapped error structure. This logic should be simplified - either remove this check entirely since the handler already handles it correctly, or if unwrapping is needed, just pass through the cause directly without re-wrapping.
                                   switch verifyResult {
                                   case .failure(let error):
                                       if let cause = error.cause, isIDTokenValidationError(cause) {
                                           return callback(.failure(MFAVerifyError(cause: cause)))
                                       }
                                       callback(.failure(error))

App/ContentViewModel.swift:68

  • The removal of WEB_AUTH_PLATFORM conditional compilation directives from the App files (ContentViewModel.swift and ContentView.swift) is not mentioned in the PR description. This appears to be an unrelated change that should either be documented in the PR description or moved to a separate PR. If this is intentional, please explain why the conditional compilation is no longer needed for these web authentication functions.
    func webLogin(presentationWindow window: Auth0WindowRepresentable? = nil) async {
        isLoading = true
        errorMessage = nil

        #if !os(tvOS) && !os(watchOS)
        do {

            let credentials = try await Auth0
                .webAuth()
                .scope("openid profile email offline_access")
                .start()

            let stored = credentialsManager.store(credentials: credentials)
            if stored {
                isAuthenticated = true
            } else {
                errorMessage = "Failed to store credentials"
            }
        } catch let error as Auth0Error {
            errorMessage = "Login failed: \(error.localizedDescription)"
        } catch {
            errorMessage = "Unexpected error: \(error.localizedDescription)"
        }
        #endif

        isLoading = false
    }

    func logout(presentationWindow window: Auth0WindowRepresentable? = nil) async {
        isLoading = true
        errorMessage = nil
        #if !os(tvOS) && !os(watchOS)
        do {
            var webAuth = Auth0.webAuth()

            if let window = window {
                webAuth = webAuth.presentationWindow(window)
            }

            try await webAuth.clearSession()

            let cleared = credentialsManager.clear()
            if cleared {
                isAuthenticated = false
                print("Logout successful")
            }
        } catch let error as Auth0Error {
            errorMessage = "Logout failed: \(error.localizedDescription)"
            print("Logout failed with error: \(error)")
        } catch {
            errorMessage = "Unexpected error: \(error.localizedDescription)"
        }
        #endif

        isLoading = false
    }

App/ContentView.swift:50

  • The removal of WEB_AUTH_PLATFORM conditional compilation directives is not mentioned in the PR description. This appears to be an unrelated change that should either be documented in the PR description or moved to a separate PR. If this is intentional, please explain why the conditional compilation is no longer needed.
            Button {
                Task {
                    #if os(macOS)
                    await viewModel.webLogin(presentationWindow: currentWindow)
                    #else
                    await viewModel.webLogin(presentationWindow: window)
                    #endif
                }
            } label: {
                VStack(spacing: 4) {
                    Text("Login")
                }
            }
            .buttonStyle(PrimaryButtonStyle())
            .disabled(viewModel.isLoading)

            Divider()
                .padding(.vertical)

            Button {
                Task {
                    #if os(macOS)
                    await viewModel.logout(presentationWindow: currentWindow)
                    #else
                    await viewModel.logout(presentationWindow: window)
                    #endif
                }

Auth0/Credentials.swift:16

  • This whitespace-only change (removing a blank line after the class declaration) appears unrelated to the PR's stated purpose of adding ID token validation. Consider either reverting this cosmetic change or explaining why it's included.
    /// Token that can be used to make authenticated requests to the specified API (the **audience** value used on login).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@NandanPrabhu NandanPrabhu marked this pull request as draft February 26, 2026 05:07
@NandanPrabhu NandanPrabhu marked this pull request as ready for review February 27, 2026 10:27
@NandanPrabhu NandanPrabhu force-pushed the id_token_validation branch from eb54193 to bfe4efb Compare March 5, 2026 11:11
@NandanPrabhu NandanPrabhu marked this pull request as draft March 6, 2026 08:40
@NandanPrabhu NandanPrabhu force-pushed the id_token_validation branch from bfe4efb to 3f25b5c Compare March 9, 2026 03:12
@NandanPrabhu NandanPrabhu marked this pull request as ready for review March 9, 2026 03:13
@NandanPrabhu NandanPrabhu force-pushed the id_token_validation branch from 3f25b5c to 736c750 Compare March 9, 2026 03:14
@sanchitmehtagit sanchitmehtagit requested a review from Copilot March 10, 2026 13:17
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@sanchitmehtagit sanchitmehtagit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits

Copy link
Copy Markdown
Contributor

@sanchitmehtagit sanchitmehtagit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@NandanPrabhu NandanPrabhu merged commit 8c99966 into develop/v3.0 Mar 13, 2026
9 checks passed
@NandanPrabhu NandanPrabhu deleted the id_token_validation branch March 13, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Swift v3.0 This label depicts this feature is part of Swift 3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants