Skip to content

Conversation

@logan-stytch
Copy link
Contributor

JWT Authentication Error Handling Improvements

New Features

Enhanced Error Information

JWT authentication failures now return detailed error information including:

  • Status code (401, 403, 500, etc.)
  • Request ID for debugging and support tickets
  • Error type and error message for better error handling
  • Error URL linking to relevant documentation

Consumer Sessions (Non-Breaking)

New JWTErrorResponse Type

A new response type has been added to provide error details when remote JWT authentication fails:

public data class JWTErrorResponse(
    val statusCode: Int,
    val requestId: String?,
    val errorType: String,
    val errorMessage: String,
    val errorUrl: String,
) : JWTResponse

Usage Example

when (val result = consumerSessions.authenticateJwt(jwt)) {
    is StytchResult.Success -> when (result.value) {
        is JWTSessionResponse -> {
            // Local JWT validation succeeded
            val session = result.value.response
        }
        is JWTAuthResponse -> {
            // Remote authentication succeeded
            val session = result.value.response.session
        }
        is JWTErrorResponse -> {
            // NEW: Remote authentication failed with details
            println("Authentication failed: ${result.value.statusCode}")
            println("Error: ${result.value.errorMessage}")
            println("Request ID: ${result.value.requestId}")
        }
        is JwtNullResponse -> {
            // Fallback for other error types (unchanged)
        }
    }
}

B2B Sessions (Breaking Change)

Migration Required

B2B JWT authentication now properly returns StytchResult.Error when remote authentication fails, instead of StytchResult.Success(null).

Before (Old Code)

when (val result = b2bSessions.authenticateJwt(jwt)) {
    is StytchResult.Success -> {
        val memberSession = result.value // Could be null on failure
        if (memberSession != null) {
            // Authentication succeeded
        } else {
            // Authentication failed - no error details available
        }
    }
    is StytchResult.Error -> {
        // Handle local JWT validation errors only
    }
}

After (New Code Required)

when (val result = b2bSessions.authenticateJwt(jwt)) {
    is StytchResult.Success -> {
        val memberSession = result.value // Never null
        // Authentication succeeded
    }
    is StytchResult.Error -> {
        when (val exception = result.exception) {
            is StytchException.Response -> {
                // NEW: Remote authentication failed with full error details
                val error = exception.reason
                println("Auth failed: ${error.statusCode} - ${error.errorMessage}")
                println("Request ID: ${error.requestId}")

                // Handle specific error types
                when (error.statusCode) {
                    401 -> handleInvalidToken()
                    403 -> handlePermissionDenied()
                    500 -> handleServerError()
                }
            }
            is StytchException.Critical -> {
                // Local JWT validation errors (unchanged)
            }
        }
    }
}

Migration Checklist

For Consumer Sessions Users

  • No action required - existing code continues to work
  • Optional: Add handling for JWTErrorResponse to get enhanced error information

For B2B Sessions Users

  • Required: Update JWT authentication error handling
  • Replace null checks with StytchResult.Error handling
  • Access error details via StytchException.Response.reason
  • Update test cases that expected Success(null)

@logan-stytch logan-stytch requested a review from a team as a code owner October 29, 2025 15:21
@logan-stytch logan-stytch merged commit b4404da into main Oct 29, 2025
3 checks passed
@logan-stytch logan-stytch deleted the logan/jwt-auth branch October 29, 2025 15:38
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