feat(auth): add scope validation to session tokens#697
Open
feat(auth): add scope validation to session tokens#697
Conversation
…hods Adds support for validating OAuth 2.0 scopes as part of session token validation, enabling easy migration to inbound apps with scope-based authorization. Changes: - Added scopeClaimName constant for OAuth 2.0 "scope" claim - Extended VerifyOptions interface to accept scopes parameter (string | string[]) - Implemented scope validation in validateJwt method with support for: - Space-separated scope strings (OAuth 2.0 standard) - Scope arrays (alternative format) - Subset validation (all required scopes must be present) - Added insufficientScopes error code (E011005) - Updated JSDoc for validateSession, refreshSession, validateAndRefreshSession, and exchangeAccessKey - Added comprehensive test coverage (11 tests) for scope validation scenarios When scopes are provided in VerifyOptions and validation fails, the method throws a JWTClaimValidationFailed error with message "insufficient scopes". Co-authored-by: Shuni <251468265+shuni-bot[bot]@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds optional OAuth2-style scope enforcement to the Node SDK’s session/JWT validation flow, enabling callers of validateSession() (and related refresh/exchange helpers) to require specific scopes on session tokens.
Changes:
- Extends
VerifyOptionsto includescopes?: string | string[]. - Adds scope-claim handling in
validateJwt()and threadsoptionsthrough session refresh/exchange paths. - Introduces
scopeClaimName = 'scope'constant and adds aninsufficientScopeserror code entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/types.ts | Adds scopes to VerifyOptions used by session/JWT verification APIs. |
| lib/index.ts | Implements scope validation in validateJwt() and documents new option usage across auth helpers. |
| lib/index.test.ts | Adds tests for scope validation behavior across validate/refresh flows. |
| lib/errors.ts | Adds insufficientScopes error code constant. |
| lib/constants.ts | Adds scopeClaimName constant for the OAuth2 scope claim. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+200
to
+201
| // Normalize required scopes to array | ||
| const requiredScopes = Array.isArray(options.scopes) ? options.scopes : [options.scopes]; |
| (sdk as any).validateSession(tokenScopeReadWrite, { scopes: ['read', 'write'] }), | ||
| ).resolves.toHaveProperty('jwt', tokenScopeReadWrite); | ||
| }); | ||
|
|
Comment on lines
+203
to
+227
| // Extract scopes from token - support both "scope" (space-separated string) and "scopes" (array) | ||
| let tokenScopes: string[] = []; | ||
| const scopeClaim = token[scopeClaimName]; | ||
| const scopesClaim = token.scopes; | ||
|
|
||
| if (typeof scopeClaim === 'string') { | ||
| // OAuth 2.0 standard: space-separated string | ||
| tokenScopes = scopeClaim.split(' ').filter((s) => s.length > 0); | ||
| } else if (Array.isArray(scopesClaim)) { | ||
| // Alternative: array of scopes | ||
| tokenScopes = scopesClaim.filter((s) => typeof s === 'string'); | ||
| } else if (Array.isArray(scopeClaim)) { | ||
| // Handle if "scope" claim is an array (non-standard but possible) | ||
| tokenScopes = scopeClaim.filter((s) => typeof s === 'string'); | ||
| } | ||
|
|
||
| // Check if all required scopes are present in token scopes | ||
| const hasAllScopes = requiredScopes.every((scope) => tokenScopes.includes(scope)); | ||
|
|
||
| if (!hasAllScopes) { | ||
| throw new errors.JWTClaimValidationFailed( | ||
| 'insufficient scopes', | ||
| scopeClaimName, | ||
| 'check_failed', | ||
| ); |
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.
Fixes descope/etc#14661
View workflow run
Summary
I've successfully implemented scope validation support for the Node SDK's
validateSession()method and related authentication functions. Here's what was done:Implementation Details
1. Core Changes:
scopeClaimNameconstant for OAuth 2.0 "scope" claim inlib/constants.tsVerifyOptionsinterface to acceptscopesparameter (supports bothstringandstring[])insufficientScopeserror code (E011005) inlib/errors.ts2. Scope Validation Logic (
lib/index.ts):The implementation in
validateJwt()supports multiple scope formats:"read write"["read", "write"]3. Updated Methods:
validateSession(sessionToken, options)- now acceptsscopesin optionsrefreshSession(refreshToken, options)- validates scopes on refreshed sessionsvalidateAndRefreshSession(sessionToken, refreshToken, options)- validates scopes during refreshexchangeAccessKey(accessKey, loginOptions, options)- validates scopes on exchanged sessionsTesting
Added 11 comprehensive tests covering:
validateSession,refreshSession,validateAndRefreshSessionTest Results: All 11 scope validation tests passing ✅
Usage Example
Error Handling
When scope validation fails, the method throws a
JWTClaimValidationFailederror with the message "insufficient scopes", which gets wrapped in a user-friendly error message.Commit
Created commit
2b3f204with all changes properly formatted and linted ✅This implementation enables easy migration to inbound apps with scope-based authorization while maintaining backward compatibility (scopes are optional).
Created by Shuni 🐕