-
Notifications
You must be signed in to change notification settings - Fork 8
Description
🐛 TL;DR
SAML SSO authentication (Entra ID) fails in v0.15.0 with CodeExchangeError: Invalid code verifier.
Works perfectly in v0.14.0. Library appears to incorrectly apply OAuth PKCE validation to SAML flows.
Bug Description
After upgrading from @workos-inc/authkit-react@0.14.0 to @workos-inc/authkit-react@0.15.0, SAML-based authentication fails with:
CodeExchangeError: Invalid code verifier.
at HttpClient.authenticateWithCode (@workos-inc_authkit-react.js:606:11)
at async Client.handleCallback_fn (@workos-inc_authkit-react.js:882:40)
at async Client.initialize (@workos-inc_authkit-react.js:752:7)
at async createClient (@workos-inc_authkit-react.js:1037:3)
Environment
- Package version:
@workos-inc/authkit-react@0.15.0 - Framework: Vite + React Router (TanStack Router)
- Authentication: SAML SSO (Entra ID / Azure AD)
- Environment: Development (localhost:3000) and Production
SSO Configuration
- Connection Type: SAML with Entra ID (Azure AD)
- Organization-based SSO: Yes (
organizationIdrequired) - Authentication Flow: Organization → SAML → WorkOS → App
Configuration
<AuthKitProvider
clientId={workosClientId}
redirectUri="http://localhost:3000" // Matches WorkOS Dashboard exactly
onRedirectCallback={({ state }) => {
if (state?.returnTo) {
sessionStorage.setItem("returnTo", state.returnTo);
}
}}
>
{/* App with organization validation */}
</AuthKitProvider>What Works ✅
- Authentication works perfectly in
v0.14.0 - SAML SSO with Entra ID is correctly configured in WorkOS Dashboard
- User successfully authenticates through Entra ID
- WorkOS receives SAML response and redirects back to app
What Fails ❌
- SAML callback handling fails with "Invalid code verifier" in
v0.15.0 - Library appears to confuse SAML flow with OAuth PKCE flow
- Only happens in
v0.15.0, works fine inv0.14.0
Steps to Reproduce
- Set up SAML SSO with Entra ID (Azure AD) in WorkOS Dashboard
- Configure organization-based authentication
- Install
@workos-inc/authkit-react@0.15.0 - Configure
AuthKitProviderwith organization ID - Attempt to sign in through SAML SSO
- Complete authentication on Entra ID
- Observe error on SAML callback
Expected Behavior
User should be authenticated successfully after SAML callback, as it does in v0.14.0.
Actual Behavior
SAML callback fails with CodeExchangeError: Invalid code verifier because the library is incorrectly attempting PKCE validation on a SAML flow.
Technical Analysis
Why this is happening:
- SAML authentication does not use OAuth code exchange
- SAML does not have
code_verifierorcode_challenge- these are OAuth/OIDC PKCE concepts - The error occurs in
HttpClient.authenticateWithCode()which is OAuth-specific - v0.15.0 appears to route SAML callbacks through OAuth code exchange logic
Evidence:
CodeExchangeError: Invalid code verifier.
at HttpClient.authenticateWithCode ← OAuth-specific method
The SAML callback should be handled by a SAML-specific handler, not the OAuth code exchange handler.
Impact
- Severity: High - Blocks authentication for all SAML SSO users
- Affected users: Anyone using SAML with Entra ID, Okta, Google Workspace, or other SAML providers
- Scope: Both development and production environments
Root Cause Hypothesis
Version 0.15.0 likely changed how it detects/handles different authentication flows. It now incorrectly treats SAML callbacks as OAuth callbacks and tries to validate a PKCE code verifier that doesn't exist in SAML.
According to v0.15.0 release notes, the version added authenticationMethod to state. This change may have affected how SAML vs OAuth flows are distinguished.
Workaround
Current solution: Pin to v0.14.0 in package.json
Code Analysis Confirmation
After reviewing the authkit-js v0.17.0 changes (PR #99), the bug is confirmed:
- Change: Added
authenticationMethodtracking todeserializeAuthenticationResponse - Bug: The callback handler doesn't check authentication flow type before calling
HttpClient.authenticateWithCode() - Impact: SAML callbacks (which have
authenticationMethod: "SSO") incorrectly go through OAuth code exchange - Result: PKCE validation fails because SAML doesn't use code verifiers
The fix requires:
Check if callback is SAML (authenticationMethod === "SSO") and route to SAML-specific handler, not OAuth authenticateWithCode().
Sources:
- authkit-js PR #99: Add authentication method to response interfaces and serializer authkit-js#99
- authkit-react PR Add authenticationMethod to state #80: Add authenticationMethod to state #80