Skip to content

Conversation

@wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Nov 25, 2025

Description

This PR adds JWT verification support for OAuth access tokens (acceptsToken: 'oauth_token')

  • Used existing JWT functions while extending verifyJwt with a headerType parameter to support OAuth access token JWTs (RFC 9068)
  • Added tests for headerType assertions, and OAuth JWT verifications

Resolves USER-4076

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Accept OAuth-style JWT access tokens and map JWT payloads into access-token objects.
    • Added JWT-format detection and helpers to recognize OAuth JWTs (multiple typ values).
  • Improvements

    • Flexible JWT header-type validation (configurable allowed types).
    • Broader token-type detection and routing to JWT verification.
    • Improved verification reporting with a new failure code plus optional status/action details.
  • Tests

    • New fixtures and tests covering OAuth JWT formats, verification flows, and error cases.
  • Chores

    • Release bump recorded in changeset.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Nov 25, 2025

🦋 Changeset detected

Latest commit: 150bb33

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@clerk/backend Minor
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Nov 25, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Nov 26, 2025 9:16pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 25, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds JWT detection and verification for OAuth access tokens across backend: new JWT helpers and fixtures, header-type assertion and VerifyJwt option, IdPOAuthAccessToken.fromJwtPayload factory, routing JWT-format machine tokens into OAuth verification flow, tests, and a new token verification failure code.

Changes

Cohort / File(s) Summary
Changeset Documentation
\.changeset/swift-sheep-notice.md
Adds a changeset marking a minor bump for @clerk/backend and documents added JWT support for the OAuth token type.
OAuth Token Model
packages/backend/src/api/resources/IdPOAuthAccessToken.ts
Adds IdPOAuthAccessToken.fromJwtPayload(payload, clockSkewInMs) and local OAuthJwtPayload mapping standard JWT claims to token fields; imports JwtPayload.
Error Handling
packages/backend/src/errors.ts
Adds TokenVerificationFailed code; makes MachineTokenVerificationError.status optional and adds action?: TokenVerificationErrorAction; updates constructor and getFullMessage.
Test Fixtures (index & machine)
packages/backend/src/fixtures/index.ts, packages/backend/src/fixtures/machine.ts
Adds mockOAuthAccessTokenJwtPayload, mockSignedOAuthAccessTokenJwt, mockSignedOAuthAccessTokenJwtApplicationTyp, and central JWT creation helpers/fixtures used by tests.
JWT Header Assertion
packages/backend/src/jwt/assertions.ts
Changes assertHeaderType(typ?, allowedTypes = 'JWT') to accept `string
JWT Verification Options & Tests
packages/backend/src/jwt/verifyJwt.ts, packages/backend/src/jwt/__tests__/*
Adds `VerifyJwtOptions.headerType?: string
Machine Token Detection & Utilities
packages/backend/src/tokens/machine.ts, packages/backend/src/tokens/__tests__/*
Adds JwtFormatRegExp, isJwtFormat(), OAUTH_ACCESS_TOKEN_TYPES, isOAuthJwt(), updates isMachineToken() and getMachineTokenType(); exports new helpers and tests them.
Request Authentication
packages/backend/src/tokens/request.ts
Replaces uses of isMachineTokenByPrefix() with isMachineToken() for token-type detection and branching; updates imports and related checks.
Token Verification (OAuth/JWT path)
packages/backend/src/tokens/verify.ts
Adds verifyJwtOAuthToken to decode/verify JWT-formatted OAuth tokens (resolve JWK/PEM, call verifyJwt, map payload to IdPOAuthAccessToken); routes JWT-format tokens into this flow and maps failures to MachineTokenVerificationError.
Token Tests (verify & machine)
packages/backend/src/tokens/__tests__/verify.test.ts, packages/backend/src/tokens/__tests__/machine.test.ts
Adds helpers createOAuthJwt, isJwtFormat/isOAuthJwt tests and verifies OAuth JWT flows (valid, invalid typ, alg none, expired, alternate typ handling); updates imports to new fixtures/helpers.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Req as Request
    participant Auth as AuthHandler
    participant Machine as MachineUtils
    participant Verify as TokenVerifier
    participant JWT as JWTUtils
    participant Model as IdPModel
    participant Err as ErrorHandler

    Req->>Auth: authenticateRequest(token)
    Auth->>Machine: isMachineToken(token)
    alt machine token (JWT-format)
        Machine-->>Auth: true
        Auth->>Verify: verifyMachineAuthToken(token)
        Verify->>Machine: isOAuthJwt(token)?
        alt OAuth JWT
            Machine-->>Verify: true
            Verify->>JWT: decodeJwt(token)
            JWT->>JWT: assertHeaderType(typ, allowedTypes)
            JWT-->>Verify: payload
            Verify->>Model: IdPOAuthAccessToken.fromJwtPayload(payload, clockSkewInMs)
            Model-->>Verify: token instance
            Verify-->>Auth: success
        else Not OAuth JWT
            Machine-->>Verify: false
            Verify->>Verify: prefix-based verification (JWK/PEM)
        end
    else not machine token
        Machine-->>Auth: false
        Auth->>Verify: session / API-key verification
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Focus areas:
    • packages/backend/src/tokens/verify.ts — new JWT decode/verify flow, JWK/PEM resolution, error mapping.
    • packages/backend/src/tokens/machine.ts — regex, isJwtFormat/isOAuthJwt, token-type resolution.
    • packages/backend/src/tokens/request.ts — branching changes relying on new predicate.
    • packages/backend/src/jwt/assertions.ts and verifyJwt.ts — headerType propagation and error messages.
    • Tests/fixtures — correctness of created mock JWTs, createJwt helpers, and expanded test coverage.

Poem

🐇 I sniffed a typ of at+jwt,

I twitched my whiskers, checked the bit,
Mapped jti and scope with glee,
Hopped the sig through verify tree,
OAuth tokens now hop home with me.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(backend): Add support for JWTs in OAuth token type' accurately and clearly summarizes the main change—adding JWT support for OAuth access tokens.
Linked Issues check ✅ Passed The PR implements JWT verification support for OAuth access tokens per USER-4076 requirements by extending verifyJwt with headerType, adding OAuth JWT detection, and including comprehensive tests.
Out of Scope Changes check ✅ Passed All changes directly support the objective of enabling JWT verification for OAuth access tokens; no out-of-scope modifications detected.

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 25, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7308

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7308

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7308

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7308

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7308

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7308

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7308

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7308

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7308

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7308

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7308

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7308

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7308

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7308

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7308

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7308

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7308

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7308

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7308

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7308

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7308

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7308

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7308

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7308

commit: 0ddb1ab

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (9)
packages/backend/src/api/resources/IdPOAuthAccessToken.ts (2)

47-63: Consider validating required JWT claims before construction.

The jti claim is used as the token id. If jti is missing or empty, the resulting token will have an empty id, which could cause issues in downstream logic that relies on token identification. Consider throwing a TokenVerificationError when required claims are missing rather than silently defaulting to empty strings.

  static fromJwtPayload(payload: JwtPayload, clockSkewInMs = 5000): IdPOAuthAccessToken {
    const oauthPayload = payload as OAuthJwtPayload;

+   if (!oauthPayload.jti) {
+     throw new TokenVerificationError({
+       reason: TokenVerificationErrorReason.TokenVerificationFailed,
+       message: 'Invalid JWT jti claim. Expected a non-empty string.',
+     });
+   }
+
    // Map JWT claims to IdPOAuthAccessToken fields
    return new IdPOAuthAccessToken(
-     oauthPayload.jti ?? '',
+     oauthPayload.jti,
      oauthPayload.client_id ?? '',

Note: The import for TokenVerificationError and TokenVerificationErrorReason would need to be added from ../errors.


5-10: Add JSDoc documentation for the OAuthJwtPayload type.

Per coding guidelines, public APIs and types should be documented with JSDoc. This type extends JwtPayload with OAuth-specific claims and would benefit from documentation explaining each field.

+/**
+ * Extended JWT payload for OAuth 2.0 access tokens per RFC 9068.
+ * @see https://www.rfc-editor.org/rfc/rfc9068.html
+ */
 type OAuthJwtPayload = JwtPayload & {
+  /** JWT ID - unique identifier for the token */
   jti?: string;
+  /** OAuth 2.0 client identifier */
   client_id?: string;
+  /** Space-delimited scope string */
   scope?: string;
+  /** Array of scope values (alternative to space-delimited scope) */
   scp?: string[];
 };
packages/backend/src/tokens/__tests__/verify.test.ts (2)

436-451: Consider removing verbose implementation comments.

These comments explain the testing rationale in detail, which is useful during development but adds noise to the test file. The test description and assertions should be self-explanatory.

    it('verifies JWT with typ application/at+jwt', async () => {
      server.use(
        http.get(
          'https://api.clerk.test/v1/jwks',
          validateHeaders(() => {
            return HttpResponse.json(mockJwks);
          }),
        ),
      );

      const validJtiPayload = {
        ...mockOAuthAccessTokenJwtPayload,
        jti: 'oat_12345678901234567890123456789012',
      };

-      // We mock verifyJwt to ensure we don't hit the real signature check failure (since we use createJwt which signs with a dummy key/algo)
-      // But we want to test headerType validation logic. The real verifyJwt does signature check LAST.
-      // assertHeaderType is called BEFORE signature check.
-      // So if we mock verifyJwt, we skip assertHeaderType inside verifyJwt unless we spy on assertions?
-      // No, VerifyJwtModule.verifyJwt IS the function we call.
-      // If we mock it, we bypass the real logic entirely.
-
-      // To test that verifyOAuthToken accepts 'application/at+jwt', we should let it call verifyJwt.
-      // But verifyJwt will fail signature if we don't provide correct key/signature.
-      // However, if we Mock verifyJwt, we are just testing verifyMachineAuthToken -> verifyOAuthToken flow, not verifyJwt internals.
-
-      // Let's rely on the fact that verifyOAuthToken calls verifyJwt with headerType: ['at+jwt', 'application/at+jwt'].
-      // We verified that call in the first test ("verifies a valid OAuth JWT").
-
-      // But we can add a test case where we simulate a successful verifyJwt call with application/at+jwt.
-
      const spy = vi.spyOn(VerifyJwtModule, 'verifyJwt').mockResolvedValueOnce({

477-491: Add more specific error assertions for invalid JWT format test.

The test only checks that errors is defined. Consider asserting on the specific error code or message to ensure the correct error path is exercised.

    it('handles invalid JWT format', async () => {
      const invalidJwt = 'invalid.jwt.token';
-      // Mock isJwt to return true so it enters verifyOAuthToken,
-      // OR rely on regex. Regex requires 3 parts.
-      // 'invalid.jwt.token' matches 3 parts.
-
-      // But decodeJwt will fail if base64 is bad.

      const result = await verifyMachineAuthToken(invalidJwt, {
        apiUrl: 'https://api.clerk.test',
        secretKey: 'a-valid-key',
      });

      expect(result.errors).toBeDefined();
+      expect(result.errors?.[0].code).toBeDefined();
    });
packages/backend/src/tokens/machine.ts (2)

18-22: Consider exporting OAUTH_ACCESS_TOKEN_TYPES for external consumers.

This constant defines RFC 9068 compliant OAuth access token types and could be useful for consumers who need to validate or generate OAuth JWTs outside of this module.

 /**
  * Valid OAuth 2.0 JWT access token type values per RFC 9068.
  * @see https://www.rfc-editor.org/rfc/rfc9068.html#section-2.1
  */
-const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'] as const;
+export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'] as const;

24-34: Optimize redundant JWT decoding in machine token detection flow.

Verified: isMachineToken() (request.ts:105) calls isOAuthJwt() which decodes the JWT, then immediately getMachineTokenType() (request.ts:106) calls isOAuthJwt() again on the same token, causing redundant parsing. Consider memoizing the decoded JWT result, combining detection and type extraction, or refactoring to avoid dual decoding in the authentication hot path.

packages/backend/src/tokens/verify.ts (3)

213-227: Redundant try-catch around decodeJwt.

decodeJwt returns a result object with { data, errors } rather than throwing exceptions. The outer try-catch on lines 215-227 is unnecessary since errors are already handled via the result pattern on lines 229-240.

Consider simplifying:

-  if (isJwt(accessToken)) {
-    let decoded: JwtReturnType<Jwt, TokenVerificationError>;
-    try {
-      decoded = decodeJwt(accessToken);
-    } catch (e) {
-      return {
-        tokenType: TokenType.OAuthToken,
-        errors: [
-          new MachineTokenVerificationError({
-            code: MachineTokenVerificationErrorCode.TokenInvalid,
-            message: (e as Error).message,
-          }),
-        ],
-      };
-    }
-
-    const { data: decodedResult, errors } = decoded;
+  if (isJwt(accessToken)) {
+    const { data: decodedResult, errors } = decodeJwt(accessToken);

282-294: Hardcoded jti format validation.

The regex /^oat_[0-9A-Za-z]{32}$/ is hardcoded here. Consider extracting this pattern to a shared constant alongside OAUTH_TOKEN_PREFIX in machine.ts for consistency and maintainability.


350-361: Remove duplicate isJwt and reuse exported isJwtFormat from machine.ts.

Both isJwt in verify.ts (lines 359-361) and isJwtFormat in machine.ts are identical—same regex pattern and logic. Replace the duplicate function and regex with an import of isJwtFormat:

-import { API_KEY_PREFIX, M2M_TOKEN_PREFIX, OAUTH_TOKEN_PREFIX } from './machine';
+import { API_KEY_PREFIX, isJwtFormat, M2M_TOKEN_PREFIX, OAUTH_TOKEN_PREFIX } from './machine';
...
-const JwtFormatRegExp = /^[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+$/;
-
-function isJwt(token: string): boolean {
-  return JwtFormatRegExp.test(token);
-}

Then update lines 213 and 350 to use isJwtFormat(...) instead of isJwt(...).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b248601 and e86c3ab.

📒 Files selected for processing (11)
  • .changeset/swift-sheep-notice.md (1 hunks)
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts (2 hunks)
  • packages/backend/src/errors.ts (2 hunks)
  • packages/backend/src/fixtures/index.ts (1 hunks)
  • packages/backend/src/jwt/assertions.ts (1 hunks)
  • packages/backend/src/jwt/verifyJwt.ts (2 hunks)
  • packages/backend/src/tokens/__tests__/machine.test.ts (2 hunks)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
  • packages/backend/src/tokens/machine.ts (4 hunks)
  • packages/backend/src/tokens/request.ts (4 hunks)
  • packages/backend/src/tokens/verify.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/jwt/assertions.ts
  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/errors.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/request.ts
  • packages/backend/src/tokens/machine.ts
  • packages/backend/src/jwt/verifyJwt.ts
  • packages/backend/src/api/resources/IdPOAuthAccessToken.ts
  • packages/backend/src/tokens/verify.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/machine.test.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/backend/src/fixtures/index.ts
🧬 Code graph analysis (5)
packages/backend/src/jwt/assertions.ts (1)
packages/backend/src/errors.ts (5)
  • TokenVerificationError (41-69)
  • TokenVerificationErrorAction (30-36)
  • TokenVerificationErrorAction (38-39)
  • TokenVerificationErrorReason (9-25)
  • TokenVerificationErrorReason (27-28)
packages/backend/src/tokens/__tests__/verify.test.ts (6)
packages/backend/src/mock-server.ts (1)
  • server (6-6)
packages/backend/src/fixtures/index.ts (2)
  • mockOAuthAccessTokenJwtPayload (36-46)
  • createJwt (49-60)
.typedoc/custom-theme.mjs (1)
  • result (171-171)
packages/backend/src/tokens/verify.ts (1)
  • verifyMachineAuthToken (340-355)
packages/backend/src/internal.ts (1)
  • verifyMachineAuthToken (57-57)
packages/backend/src/api/resources/IdPOAuthAccessToken.ts (1)
  • IdPOAuthAccessToken (12-65)
packages/backend/src/tokens/request.ts (1)
packages/backend/src/tokens/machine.ts (1)
  • isMachineToken (56-58)
packages/backend/src/tokens/machine.ts (2)
packages/backend/src/jwt/verifyJwt.ts (1)
  • decodeJwt (45-95)
packages/backend/src/internal.ts (1)
  • isMachineTokenByPrefix (59-59)
packages/backend/src/jwt/verifyJwt.ts (3)
packages/backend/src/jwt/types.ts (1)
  • JwtReturnType (3-11)
packages/backend/src/errors.ts (1)
  • TokenVerificationError (41-69)
packages/backend/src/jwt/assertions.ts (1)
  • assertHeaderType (50-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (33)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15, RQ)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, shared, clerk-js, RQ)
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (12)
packages/backend/src/tokens/__tests__/machine.test.ts (1)

98-139: Good test coverage for new JWT utilities.

The tests comprehensively cover:

  • Valid/invalid JWT format detection with boundary cases
  • OAuth JWT type detection for both RFC 9068 compliant typ values (at+jwt and application/at+jwt)
  • Edge cases like malformed JWT strings
packages/backend/src/jwt/assertions.ts (1)

50-63: LGTM!

The enhanced assertHeaderType function maintains backward compatibility with the default 'JWT' value while supporting multiple allowed header types for OAuth JWT verification. The implementation correctly normalizes the input to an array and provides a clear error message.

packages/backend/src/jwt/verifyJwt.ts (1)

122-127: LGTM!

The headerType option is well-documented with an RFC reference, properly typed, and cleanly integrated into the verification flow.

packages/backend/src/errors.ts (1)

73-110: LGTM!

The error handling extensions are well-structured:

  • New TokenVerificationFailed code for OAuth JWT verification errors
  • Optional status and action fields maintain backward compatibility
  • The getFullMessage() gracefully handles missing status with 'n/a'
packages/backend/src/tokens/machine.ts (1)

50-58: Good implementation of combined machine token detection.

The isMachineToken function cleanly combines prefix-based detection with OAuth JWT recognition, properly extending machine token handling to support JWT-format OAuth tokens.

packages/backend/src/tokens/request.ts (4)

17-17: LGTM!

The import update correctly reflects the new isMachineToken predicate which now includes OAuth JWT detection alongside prefix-based machine token detection.


101-113: LGTM!

The function correctly uses isMachineToken to determine token type, which now properly handles both prefix-based machine tokens and OAuth JWTs.


699-732: LGTM!

The guard at line 707 correctly rejects non-machine tokens when the endpoint expects machine tokens. The updated predicate ensures OAuth JWTs are now recognized as valid machine tokens and routed to verifyMachineAuthToken.


734-774: LGTM!

The authenticateAnyRequestWithTokenInHeader function correctly uses isMachineToken at line 742 to route OAuth JWTs through the machine token verification path, while regular session JWTs continue through verifyToken.

packages/backend/src/tokens/verify.ts (1)

264-268: Good addition: JWT header type validation for OAuth tokens.

The headerType: ['at+jwt', 'application/at+jwt'] option correctly validates that the JWT header type conforms to RFC 9068 for access tokens.

packages/backend/src/fixtures/index.ts (2)

48-60: LGTM!

The createJwt helper is well-designed with sensible defaults and proper base64url encoding. The type definition allows flexible override of header, payload, and signature.


62-65: LGTM!

The mockOAuthAccessTokenJwt correctly uses typ: 'at+jwt' header which aligns with the RFC 9068 validation in verifyOAuthToken.

@wobsoriano wobsoriano changed the title feat(backend): Add support to JWTs in oauth token type feat(backend): Add support for JWTs in OAuth token type Nov 25, 2025
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/backend/src/tokens/__tests__/verify.test.ts (2)

402-421: Consider mocking verifyJwt for deterministic type validation testing.

Unlike other tests in this block, this test doesn't mock verifyJwt. The test relies on the real verification flow, but the mock JWT signature likely won't pass cryptographic verification, potentially failing before the headerType check. Consider mocking verifyJwt to return an error specifically for the type mismatch to ensure this test validates the intended behavior.

     it('fails if JWT type is not at+jwt or application/at+jwt', async () => {
-      server.use(
-        http.get(
-          'https://api.clerk.test/v1/jwks',
-          validateHeaders(() => {
-            return HttpResponse.json(mockJwks);
-          }),
-        ),
-      );
-
+      vi.spyOn(VerifyJwtModule, 'verifyJwt').mockResolvedValueOnce({
+        errors: [{ message: 'Invalid JWT type "JWT". Expected "at+jwt" or "application/at+jwt".' }],
+      });
+
       const oauthJwt = createOAuthJwt(mockOAuthAccessTokenJwtPayload, 'JWT'); // Wrong type

       const result = await verifyMachineAuthToken(oauthJwt, {
         apiUrl: 'https://api.clerk.test',
         secretKey: 'a-valid-key',
       });

       expect(result.errors).toBeDefined();
       expect(result.errors?.[0].message).toContain('Invalid JWT type');
     });

460-469: Strengthen the assertion to verify the specific error.

The current assertion only checks that errors is defined. Consider validating the error code and/or message for more robust testing, similar to other error cases in this file.

     it('handles invalid JWT format', async () => {
       const invalidJwt = 'invalid.jwt.token';

       const result = await verifyMachineAuthToken(invalidJwt, {
         apiUrl: 'https://api.clerk.test',
         secretKey: 'a-valid-key',
       });

       expect(result.errors).toBeDefined();
+      expect(result.errors?.[0].code).toBe('token-invalid');
     });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e86c3ab and 1b6de49.

📒 Files selected for processing (3)
  • .changeset/swift-sheep-notice.md (1 hunks)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
  • packages/backend/src/tokens/verify.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/swift-sheep-notice.md
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/__tests__/verify.test.ts (4)
packages/backend/src/fixtures/index.ts (2)
  • mockOAuthAccessTokenJwtPayload (36-46)
  • createJwt (49-60)
packages/backend/src/mock-server.ts (2)
  • server (6-6)
  • validateHeaders (9-47)
packages/backend/src/tokens/verify.ts (1)
  • verifyMachineAuthToken (340-355)
packages/backend/src/api/resources/IdPOAuthAccessToken.ts (1)
  • IdPOAuthAccessToken (12-65)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (32)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 15, RQ)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (handshake:staging, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, shared, clerk-js, RQ)
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (10)
packages/backend/src/tokens/__tests__/verify.test.ts (4)

11-20: LGTM! Well-structured test helper.

The helper function is appropriately scoped to the test file and provides a clean API for creating test JWTs with configurable typ header values.


330-373: LGTM! Comprehensive test for valid OAuth JWT verification.

The test correctly validates the token structure, data fields, and ensures verifyJwt is called with the expected headerType values.


375-400: LGTM!

Correctly tests the jti validation logic with a mock that bypasses signature verification.


423-458: LGTM!

Good coverage for the alternative application/at+jwt typ value.

packages/backend/src/tokens/verify.ts (6)

3-5: LGTM!

Import changes correctly add the Jwt type and adjust import structure for IdPOAuthAccessToken (now imported as a value for its static method usage).


213-240: LGTM!

The JWT decoding and error handling follows the established pattern. The try-catch provides a defensive layer even though decodeJwt returns a result object.


242-262: LGTM!

JWK resolution logic correctly follows the established pattern from verifyToken.


264-280: LGTM!

Correctly validates both at+jwt and application/at+jwt typ values per RFC 9068.


296-309: LGTM!

Token creation and error handling are correct. The clockSkewInMs parameter is properly passed to align expiration calculations.


350-352: LGTM!

JWT-format tokens are correctly routed to OAuth verification as a fallback after prefix checks.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/backend/src/tokens/verify.ts (1)

281-295: Confirm OAuth JWT jti format assumptions before finalizing the regex

The jti validation currently accepts any oat_-prefixed alphanumeric string:

if (!jti || !/^oat_[0-9A-Za-z]+$/.test(jti)) {
  // ...
}

A previous review noted that production OAuth access token IDs may be fixed-length (e.g. exactly 32 chars after oat_), and recommended tightening this regex accordingly, along with adjusting the default fixture value. Before merging, please double‑check the actual IdP OAuth access token ID format and decide whether this regex should enforce a fixed length (e.g. {32}) to match real IDs, or if variable length is intentional.

🧹 Nitpick comments (2)
packages/backend/src/tokens/__tests__/verify.test.ts (1)

329-460: JWT OAuth tests cover key paths; consider tightening the invalid-format assertion

The new verifyOAuthToken with JWT suite nicely exercises:

  • happy path (including headerType propagation),
  • invalid jti,
  • invalid typ,
  • alternate typ (application/at+jwt),
  • and structurally invalid JWTs.

For the "handles invalid JWT format" test, you currently only assert that result.errors is defined. If you want stronger regression protection, you could also assert the machine error code (e.g. token-invalid) or part of the message, so future changes to error mapping don’t silently weaken guarantees.

packages/backend/src/tokens/verify.ts (1)

212-308: Ensure error returns in the JWT OAuth path consistently populate data

The new JWT-specific branch in verifyOAuthToken is structurally sound: it:

  • guards with isJwtFormat,
  • decodes the JWT with a defensive try/catch,
  • resolves the JWK using jwtKey or secretKey,
  • reuses verifyJwt with headerType: ['at+jwt', 'application/at+jwt'],
  • validates jti before mapping via IdPOAuthAccessToken.fromJwtPayload.

One small inconsistency: several error paths in this branch return only { tokenType, errors } without data, while other helpers (like handleClerkAPIError) always set data: undefined on failures. For a discriminated MachineTokenReturnType, consistently including data: undefined in all error cases makes the runtime shape predictable and avoids subtle checks on the presence of the data property.

You can align these branches by populating data: undefined wherever you return errors, e.g.:

-      return {
-        tokenType: TokenType.OAuthToken,
-        errors: [
+      return {
+        data: undefined,
+        tokenType: TokenType.OAuthToken,
+        errors: [
           new MachineTokenVerificationError({
             code: MachineTokenVerificationErrorCode.TokenInvalid,
             message: (e as Error).message,
           }),
         ],
       };

and similarly for the other error returns in this JWT block (errors from decodeJwt, JWK resolution failures, verifyJwt failures, invalid jti, and the outer catch).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1b6de49 and bf6d6e2.

📒 Files selected for processing (2)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
  • packages/backend/src/tokens/verify.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/verify.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/verify.ts (4)
packages/backend/src/tokens/machine.ts (1)
  • isJwtFormat (14-16)
packages/backend/src/jwt/verifyJwt.ts (2)
  • decodeJwt (45-95)
  • verifyJwt (129-187)
packages/backend/src/tokens/tokenTypes.ts (2)
  • TokenType (1-6)
  • TokenType (11-11)
packages/backend/src/tokens/keys.ts (2)
  • loadClerkJwkFromPem (52-86)
  • loadClerkJWKFromRemote (131-173)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/backend/src/tokens/__tests__/verify.test.ts (1)

5-20: JWT fixtures import and createOAuthJwt helper look good

Localizing the OAuth JWT builder in the test file and parameterizing typ gives you flexible coverage without coupling tests too tightly to fixtures. Defaulting the payload to mockOAuthAccessTokenJwtPayload is reasonable here since the tests don’t mutate it.

packages/backend/src/tokens/verify.ts (2)

2-5: Type imports and value imports are aligned with shared types usage

Switching to @clerk/shared/types for Jwt, JwtPayload, and Simplify, and importing IdPOAuthAccessToken as a value from ../api, matches the guideline to prefer shared types and keeps tree‑shaking friendly exports.

Also applies to: 18-18


349-351: JWT-format routing in verifyMachineAuthToken is consistent with OAuth JWT support

Adding the isJwtFormat branch here:

if (isJwtFormat(token)) {
  return verifyOAuthToken(token, options);
}

makes verifyMachineAuthToken handle both opaque OAuth IDs (oat_…) and bare OAuth JWTs. Given the earlier prefix checks for M2M, OAuth, and API keys, this shouldn’t interfere with existing machine token flows and keeps the new JWT behavior nicely encapsulated in verifyOAuthToken.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/backend/src/fixtures/index.ts (1)

48-66: Tighten CreateJwt option types to avoid any and clarify API surface

The createJwt logic is good, but the current signature uses any for header and payload, which goes against the repo’s TypeScript guidelines and reduces type safety. You can keep the same runtime behavior while improving typings with a small refactor, e.g.:

-type CreateJwt = (opts?: { header?: any; payload?: any; signature?: string }) => string;
-export const createJwt: CreateJwt = ({ header, payload, signature = mockJwtSignature } = {}) => {
+type CreateJwtOptions = {
+  header?: Record<string, unknown>;
+  payload?: Record<string, unknown>;
+  signature?: string;
+};
+
+type CreateJwt = (opts?: CreateJwtOptions) => string;
+
+export const createJwt: CreateJwt = ({ header, payload, signature = mockJwtSignature } = {}) => {
   const encoder = new TextEncoder();

This keeps the helper flexible for tests while avoiding any and making the API a bit clearer. As per coding guidelines, this better aligns with the “no any types” and “use proper type annotations” recommendations.

After adjusting the types, please run the existing TypeScript build/tests (e.g., pnpm build or pnpm test) to confirm there are no downstream type errors where createJwt is used.

packages/backend/src/tokens/verify.ts (1)

214-226: Remove redundant try-catch around decodeJwt.

The decodeJwt function returns errors via JwtReturnType<Jwt, TokenVerificationError> and doesn't throw exceptions (see packages/backend/src/jwt/verifyJwt.ts). The error handling at lines 228-239 already covers the error case. The try-catch here only catches unexpected runtime errors, adding unnecessary nesting.

Apply this diff to simplify the error handling:

-    let decoded: JwtReturnType<Jwt, TokenVerificationError>;
-    try {
-      decoded = decodeJwt(accessToken);
-    } catch (e) {
-      return {
-        tokenType: TokenType.OAuthToken,
-        errors: [
-          new MachineTokenVerificationError({
-            code: MachineTokenVerificationErrorCode.TokenInvalid,
-            message: (e as Error).message,
-          }),
-        ],
-      };
-    }
-
-    const { data: decodedResult, errors } = decoded;
+    const { data: decodedResult, errors } = decodeJwt(accessToken);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bf6d6e2 and 41b1c73.

📒 Files selected for processing (2)
  • packages/backend/src/fixtures/index.ts (1 hunks)
  • packages/backend/src/tokens/verify.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/verify.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/backend/src/fixtures/index.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/verify.ts (5)
packages/backend/src/tokens/machine.ts (2)
  • isJwtFormat (14-16)
  • OAUTH_TOKEN_PREFIX (7-7)
packages/backend/src/jwt/types.ts (1)
  • JwtReturnType (3-11)
packages/backend/src/jwt/verifyJwt.ts (2)
  • decodeJwt (45-95)
  • verifyJwt (129-187)
packages/backend/src/tokens/tokenTypes.ts (2)
  • TokenType (1-6)
  • TokenType (11-11)
packages/backend/src/tokens/keys.ts (2)
  • loadClerkJwkFromPem (52-86)
  • loadClerkJWKFromRemote (131-173)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (6)
packages/backend/src/fixtures/index.ts (1)

36-46: OAuth access token JWT payload fixture looks consistent

The payload structure looks solid for an OAuth access token JWT: it reuses the base claims, overrides iss/sub, adds client_id, scope, and jti, and keeps nbf < iat < exp with a short-lived TTL. The jti value now conforms to the expected oat_ + 32‑character suffix format used in verification logic.

packages/backend/src/tokens/verify.ts (5)

2-2: LGTM: Import changes are correct.

The import modifications appropriately support the JWT verification feature. Jwt is correctly imported as a type, IdPOAuthAccessToken is imported as a value (required for the .fromJwtPayload() call), and isJwtFormat is added for routing logic.

Also applies to: 4-4, 18-18


245-279: LGTM: Key resolution and JWT verification logic.

The key resolution follows the same pattern as verifyToken (lines 117-132), ensuring consistency. The headerType validation with ['at+jwt', 'application/at+jwt'] correctly enforces RFC 9068 OAuth 2.0 Access Token JWT format requirements. Error handling appropriately wraps verification failures with MachineTokenVerificationError.


295-297: LGTM: Token creation from JWT payload.

The call to IdPOAuthAccessToken.fromJwtPayload(payload, options.clockSkewInMs) correctly maps the verified JWT payload to the token structure. The timestamp unit issue mentioned in past reviews was addressed in commit bc57e96.


343-343: LGTM: Enhanced routing logic for JWT-format OAuth tokens.

Adding isJwtFormat(token) to the routing condition correctly handles OAuth tokens in JWT format (not just prefix-based tokens). This enables the new JWT verification path while maintaining backward compatibility with existing prefix-based OAuth tokens.


212-309: Comprehensive error handling in JWT verification flow.

The error handling throughout the new JWT verification logic is well-structured with specific error codes for each failure scenario (decode, key resolution, verification, jti validation). The catch-all handler at lines 298-308 appropriately wraps unexpected errors, and all error returns maintain a consistent structure matching existing token verification functions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/backend/src/tokens/__tests__/verify.test.ts (2)

5-7: Consider restoring verifyJwt spies between tests to avoid cross-test leakage

Each test creates a new vi.spyOn(VerifyJwtModule, 'verifyJwt'), but the spies are never restored. While using mockResolvedValueOnce means later calls still hit the real implementation, keeping the spy installed can leak into other test files sharing the same module cache. Adding vi.restoreAllMocks() in an afterEach for this file (or spy.mockRestore() in each test) would make the isolation explicit without changing behavior.

Please re-run the suite with vi.restoreAllMocks() enabled to confirm no hidden coupling on the spied function.


11-20: Helper is solid; consider reusing the existing KID constant instead of duplicating it

createOAuthJwt is a nice focused helper and the typ union matches the test cases. To avoid a hard-coded KID string that can drift from mockJwtHeader.kid, you could read it from mockJwtHeader (or omit it entirely and let createJwt’s default header provide it). This keeps fixtures consistent if the header KID ever changes.

packages/backend/src/fixtures/index.ts (1)

48-60: Tighten CreateJwt parameter types instead of using any

createJwt is a handy shared helper, but the header?: any; payload?: any; in CreateJwt are looser than necessary. You can avoid any while still keeping the fixture flexible by using a simple index signature type, e.g.:

-type CreateJwt = (opts?: { header?: any; payload?: any; signature?: string }) => string;
+interface JwtFixtureHeader {
+  [key: string]: unknown;
+}
+
+interface JwtFixturePayload {
+  [key: string]: unknown;
+}
+
+type CreateJwt = (opts?: {
+  header?: JwtFixtureHeader;
+  payload?: JwtFixturePayload;
+  signature?: string;
+}) => string;

This keeps the helper ergonomics the same but respects the “no any without justification” guideline.

As per coding guidelines, avoiding any improves type safety even in test fixtures.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 41b1c73 and fed6afb.

📒 Files selected for processing (2)
  • packages/backend/src/fixtures/index.ts (1 hunks)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/fixtures/index.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/backend/src/fixtures/index.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/__tests__/verify.test.ts (4)
packages/backend/src/fixtures/index.ts (3)
  • mockOAuthAccessTokenJwtPayload (36-46)
  • createJwt (49-60)
  • mockJwks (78-80)
packages/backend/src/mock-server.ts (2)
  • server (6-6)
  • validateHeaders (9-47)
packages/backend/src/tokens/verify.ts (1)
  • verifyMachineAuthToken (339-351)
packages/backend/src/api/resources/IdPOAuthAccessToken.ts (1)
  • IdPOAuthAccessToken (12-65)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: Integration Tests (nextjs, chrome, 16)
  • GitHub Check: Integration Tests (quickstart, chrome, 15)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome, 16)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (machine, chrome, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 15, RQ)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (billing, chrome, RQ)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (sessions:staging, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/backend/src/tokens/__tests__/verify.test.ts (1)

329-460: New OAuth JWT tests give good coverage of the JWT-based OAuth verification flow

The verifyOAuthToken with JWT suite cleanly exercises:

  • happy-path JWT verification (including IdPOAuthAccessToken mapping),
  • invalid jti handling,
  • invalid typ rejection,
  • support for both at+jwt and application/at+jwt,
  • and malformed JWTs.

The use of vi.spyOn(VerifyJwtModule, 'verifyJwt') to isolate headerType wiring and payload mapping is appropriate, and the expectations on headerType align with the new behavior.

packages/backend/src/fixtures/index.ts (2)

36-46: OAuth JWT payload fixture matches the verification and mapping requirements

mockOAuthAccessTokenJwtPayload cleanly extends mockJwtPayload with iss, sub, client_id, scope, and a well-formed jti, plus adjusted exp/iat/nbf. This lines up with the expectations in IdPOAuthAccessToken.fromJwtPayload (including scope → scopes array splitting) and the jti format validation used in the OAuth token verification logic.


62-65: mockOAuthAccessTokenJwt helper is a good reusable fixture for OAuth JWT tests

Exporting mockOAuthAccessTokenJwt built via createJwt with typ: 'at+jwt' and the shared OAuth payload is useful for tests that don’t need to vary header or claims. It keeps JWT construction consistent with other fixtures and centralizes the payload setup.

Copy link
Contributor

@jfoshee jfoshee left a comment

Choose a reason for hiding this comment

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

Overall this looks good to me. Personally I would move the new block of code in verifyOAuthToken to a separate function like

if (isJwtFormat(accessToken)) {
  return verifyJwtAccessToken(...);
}

For approval I defer to the JS team. Thanks for the quick work! 🚀

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
packages/backend/src/tokens/machine.ts (1)

22-22: Add as const assertion for literal type safety.

The OAUTH_ACCESS_TOKEN_TYPES array should be declared with as const to create a readonly tuple with literal types. This enables better type inference and eliminates the need for type assertions at usage sites (like line 30).

Apply this diff:

-export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'];
+export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'] as const;

Based on coding guidelines: "Use const assertions with as const for literal types" and "Declare readonly arrays and objects for immutable data structures."

packages/backend/src/tokens/__tests__/verify.test.ts (5)

11-19: Helper createOAuthJwt reads well; consider explicit return type

The helper nicely centralizes construction of OAuth JWTs and constrains typ to allowed values. For consistency with the TS guidelines, you could optionally add an explicit : string return type.

-function createOAuthJwt(
+function createOAuthJwt(
   payload = mockOAuthAccessTokenJwtPayload,
   typ: 'at+jwt' | 'application/at+jwt' | 'JWT' = 'at+jwt',
-) {
+): string {
   return createJwt({
     header: { typ, kid: 'ins_2GIoQhbUpy0hX7B2cVkuTMinXoD' },
     payload,
   });
 }

328-367: Valid OAuth JWT test and verifyJwt spy give good coverage; consider spying without stubbing

This test does a good job of verifying the JWT→IdPOAuthAccessToken mapping and asserting that headerType includes both 'at+jwt' and 'application/at+jwt'. Since JWKS responses are already mocked, you might consider using vi.spyOn(VerifyJwtModule, 'verifyJwt') without mockResolvedValueOnce(...) so the real implementation runs while still asserting on headerType, giving a slightly stronger integration test.

const spy = vi.spyOn(VerifyJwtModule, 'verifyJwt');
// no mockResolvedValueOnce call, rely on real verifyJwt + existing JWKS mock

Please verify that running the real verifyJwt here doesn’t introduce unwanted flakiness or test runtime issues in your environment.


369-388: Invalid typ test is clear; optionally assert on error code as well

The test correctly ensures JWTs with typ: 'JWT' are rejected and surfaces an “Invalid JWT type” message. For parity with other error-path tests in this file, you could also assert on an error code (if one is set for this condition) to stabilize the contract beyond message text.

expect(result.errors?.[0].code).toBe('token-invalid'); // or the specific code used in implementation

Please confirm the actual error code used in the implementation before adding this assertion.


390-420: application/at+jwt coverage looks good; minor duplication only

This test nicely mirrors the at+jwt happy path and confirms that both header types route through verifyJwt with the expected headerType array. The duplication with the first test is small and acceptable; if this pattern grows, you might later refactor into a table-driven/parameterized test.


422-431: Invalid JWT format test covers a key edge case; consider tightening expectations

Asserting that result.errors is defined for structurally invalid JWTs is useful. If the implementation exposes a specific error message or code for malformed tokens, you could optionally assert on that as well to avoid false positives from unrelated failures (e.g., network issues).

expect(result.errors?.[0].message).toContain('Invalid JWT'); // or more precise text
// and/or
expect(result.errors?.[0].code).toBe('token-invalid'); // depending on implementation

Verify the actual shape of errors for malformed JWTs before tightening these assertions.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f8645f3 and 2eccc33.

📒 Files selected for processing (3)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
  • packages/backend/src/tokens/machine.ts (4 hunks)
  • packages/backend/src/tokens/verify.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/backend/src/tokens/verify.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
  • packages/backend/src/tokens/machine.ts
🧬 Code graph analysis (2)
packages/backend/src/tokens/__tests__/verify.test.ts (4)
packages/backend/src/fixtures/index.ts (2)
  • mockOAuthAccessTokenJwtPayload (36-46)
  • createJwt (49-60)
packages/backend/src/mock-server.ts (2)
  • server (6-6)
  • validateHeaders (9-47)
packages/backend/src/tokens/verify.ts (1)
  • verifyMachineAuthToken (336-348)
packages/backend/src/api/resources/IdPOAuthAccessToken.ts (1)
  • IdPOAuthAccessToken (12-65)
packages/backend/src/tokens/machine.ts (2)
packages/backend/src/jwt/verifyJwt.ts (1)
  • decodeJwt (45-95)
packages/backend/src/internal.ts (1)
  • isMachineTokenByPrefix (59-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (5)
packages/backend/src/tokens/machine.ts (2)

1-1: LGTM! Import correctly added for JWT decoding.

The decodeJwt import is appropriately added to support the new OAuth JWT verification functionality.


76-78: LGTM! OAuth token detection correctly enhanced.

The condition properly handles both prefix-based OAuth tokens (oat_ prefix) and JWT-formatted OAuth access tokens, maintaining backwards compatibility while adding the new JWT support.

packages/backend/src/tokens/__tests__/verify.test.ts (3)

5-7: New JWT fixture and verifyJwt imports are appropriate

Using createJwt and mockOAuthAccessTokenJwtPayload from ../../fixtures plus a module import for VerifyJwtModule is consistent with existing patterns and enables clean spying on verifyJwt without affecting type-only imports. No changes needed here.


433-455: alg: "none" rejection test is solid

This test clearly verifies that JWTs using alg: 'none' are rejected and that an “Invalid JWT algorithm” message is surfaced. This is an important security check and is well-covered here.


457-481: Expired OAuth JWT behavior appropriately validated

The test for expired JWTs correctly manipulates exp relative to iat and asserts that verification produces an error mentioning expiration. This provides good coverage for time-based validation in the OAuth JWT path.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/backend/src/tokens/machine.ts (1)

29-30: Add explicit data check for type safety.

The decodeJwt return type is a discriminated union where data may be undefined when errors is present. While the short-circuit logic handles this at runtime, adding an explicit !!data check improves type safety and makes the defensive coding intention clear.

     const { data, errors } = decodeJwt(token);
-    return !errors && OAUTH_ACCESS_TOKEN_TYPES.includes(data.header.typ as (typeof OAUTH_ACCESS_TOKEN_TYPES)[number]);
+    return !errors && !!data && OAUTH_ACCESS_TOKEN_TYPES.includes(data.header.typ as (typeof OAUTH_ACCESS_TOKEN_TYPES)[number]);
🧹 Nitpick comments (1)
packages/backend/src/tokens/machine.ts (1)

22-22: Add as const for proper type inference.

Without as const, the array type is inferred as string[], making the type cast on line 30 effectively string rather than the intended union 'at+jwt' | 'application/at+jwt'.

-export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'];
+export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'] as const;

As per coding guidelines: "Use const assertions with as const for literal types".

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2eccc33 and 4550c8d.

📒 Files selected for processing (1)
  • packages/backend/src/tokens/machine.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/machine.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/machine.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/machine.ts (2)
packages/backend/src/jwt/verifyJwt.ts (1)
  • decodeJwt (45-95)
packages/backend/src/internal.ts (1)
  • isMachineTokenByPrefix (59-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/backend/src/tokens/machine.ts (3)

12-16: Looks good.

The regex correctly matches the JWT structure (three non-empty base64url-encoded segments separated by dots), and the helper function is clear and concise.


50-58: LGTM!

The updated JSDoc accurately reflects the implementation, and the logic correctly combines prefix-based and OAuth JWT detection.


76-78: LGTM!

Correctly extends OAuth token detection to include JWT-format OAuth access tokens alongside prefix-based tokens.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
packages/backend/src/fixtures/machine.ts (1)

69-81: OAuth JWT fixtures look consistent; consider documenting/allowlisting for secret scanners.

The two new JWT fixtures appear coherent with the rest of the fixtures:

  • Header typ values ("at+jwt" and "application/at+jwt") match the new test expectations.
  • Payload fields (client_id, sub, jti, iat, exp, scope) align with mockOAuthAccessTokenJwtPayload and the assertions in verify.test.ts.

Given that these are full JWT strings, tools like gitleaks will flag them. Since they’re signed with the existing test keys in this repo and target example/test issuers, that’s fine from a security perspective, but you may want to:

  • Add a brief comment that these are non-production test tokens only, and/or
  • Add them to your secret-scanning allowlist if CI is noisy on these literals.
packages/backend/src/tokens/__tests__/verify.test.ts (2)

14-22: Helper correctly builds OAuth JWTs; optional explicit return type.

createOAuthJwt cleanly wraps createJwt with the correct typ and kid and defaults the payload to the OAuth-access-token fixture. For readability and stricter typing, you could optionally annotate the return type as string:

function createOAuthJwt(
  payload = mockOAuthAccessTokenJwtPayload,
  typ: 'at+jwt' | 'application/at+jwt' | 'JWT' = 'at+jwt',
): string {
  return createJwt({ header: { typ, kid: 'ins_2GIoQhbUpy0hX7B2cVkuTMinXoD' }, payload });
}

331-468: JWT OAuth verification tests are thorough and aligned with fixtures.

This block exercises the key JWT paths well:

  • Valid OAuth JWT (typ at+jwt) with full field mapping checks (id from jti, clientId, subject, scopes).
  • Negative cases for wrong typ, invalid JWT structure, alg: "none", and expiry.
  • Additional positive for typ: "application/at+jwt".

Timer setup and JWKS mocking are consistent with the rest of the suite, and routing through verifyMachineAuthToken validates the complete machine-token flow.

If you want even stronger guarantees, you could also assert the error codes (in addition to messages) for the failure cases, but that’s optional.

packages/backend/src/fixtures/index.ts (1)

36-60: OAuth-access-token payload and JWT builder are coherent; consider tightening CreateJwt types.

  • mockOAuthAccessTokenJwtPayload cleanly overlays OAuth-specific claims on mockJwtPayload (issuer, subject, client_id, scope, jti, and coherent exp/iat/nbf), and matches what the JWT-based tests assert against.
  • createJwt correctly merges custom header/payload into the defaults and emits a compact base64url-encoded JWT using the shared mock signature, which keeps test JWT construction centralized.

For slightly stronger typing, you could replace the any fields in CreateJwt with unknown or a minimal header/payload shape, but given this is a fixtures module used only in tests, the current form is acceptable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4550c8d and d0d47ba.

📒 Files selected for processing (3)
  • packages/backend/src/fixtures/index.ts (1 hunks)
  • packages/backend/src/fixtures/machine.ts (1 hunks)
  • packages/backend/src/tokens/__tests__/verify.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/fixtures/machine.ts
  • packages/backend/src/fixtures/index.ts
  • packages/backend/src/tokens/__tests__/verify.test.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/backend/src/fixtures/index.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/tokens/__tests__/verify.test.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/__tests__/verify.test.ts (3)
packages/backend/src/fixtures/index.ts (3)
  • mockOAuthAccessTokenJwtPayload (36-46)
  • createJwt (49-60)
  • mockJwtPayload (26-34)
packages/backend/src/tokens/verify.ts (1)
  • verifyMachineAuthToken (336-348)
packages/backend/src/fixtures/machine.ts (2)
  • mockSignedOAuthAccessTokenJwt (73-74)
  • mockSignedOAuthAccessTokenJwtApplicationTyp (80-81)
🪛 Gitleaks (8.29.0)
packages/backend/src/fixtures/machine.ts

[high] 74-74: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 81-81: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/backend/src/tokens/__tests__/verify.test.ts (1)

5-10: Imports are appropriate and minimal.

The new fixture imports are directly used by the JWT tests and keep dependencies localized to the existing fixtures modules. No issues here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/backend/src/jwt/__tests__/verifyJwt.test.ts (2)

136-177: Header-type success-path coverage for JWT and OAuth JWTs looks solid

The new tests exercising:

  • default headerType (implicit "JWT"),
  • explicit headerType: 'JWT', and
  • OAuth access-token JWTs with headerType: ['at+jwt', 'application/at+jwt'] for both at+jwt and application/at+jwt headers,

nicely cover the primary “happy paths” for both Clerk JWTs and OAuth access tokens. Assertions on sub for the OAuth tokens are a good sanity check that the correct payload is being returned. No changes needed here.

You could optionally de-duplicate the “default headerType = JWT” case with the earlier “returns the valid JWT payload...” test by either:

  • repurposing the earlier test’s description to explicitly mention the default header type, or
  • combining expectations if you want a single canonical “default JWT” test.
    No diff suggested since this is purely about test organization/readability.

179-219: Negative-path headerType tests are correct; consider asserting error metadata too

The three negative tests:

  • JWT with headerType: 'at+jwt',
  • OAuth JWT with headerType: 'JWT', and
  • JWT with custom typ against ['at+jwt', 'application/at+jwt'],

correctly validate that:

  • verifyJwt surfaces the Invalid JWT type error from assertHeaderType, and
  • the error message reflects the configured allowed types (Expected "at+jwt", Expected "JWT", Expected "at+jwt, application/at+jwt"), matching the implementation that joins allowedTypes.

To make these tests a bit more robust against message-text changes and to assert contract-level semantics, you might also check the error’s reason (and optionally action) where available, similar to earlier tests using invalidTokenError. For example:

   it('rejects JWT when headerType does not match', async () => {
@@
-    const { errors: [error] = [] } = await verifyJwt(mockJwt, inputVerifyJwtOptions);
-    expect(error).toBeDefined();
-    expect(error?.message).toContain('Invalid JWT type');
-    expect(error?.message).toContain('Expected "at+jwt"');
+    const { errors: [error] = [] } = await verifyJwt(mockJwt, inputVerifyJwtOptions);
+    expect(error).toBeDefined();
+    expect(error?.reason).toBe('token-invalid');
+    expect(error?.message).toContain('Invalid JWT type');
+    expect(error?.message).toContain('Expected "at+jwt"');
   });
@@
   it('rejects OAuth JWT when headerType does not match', async () => {
@@
-    const { errors: [error] = [] } = await verifyJwt(mockSignedOAuthAccessTokenJwt, inputVerifyJwtOptions);
-    expect(error).toBeDefined();
-    expect(error?.message).toContain('Invalid JWT type');
-    expect(error?.message).toContain('Expected "JWT"');
+    const { errors: [error] = [] } = await verifyJwt(mockSignedOAuthAccessTokenJwt, inputVerifyJwtOptions);
+    expect(error).toBeDefined();
+    expect(error?.reason).toBe('token-invalid');
+    expect(error?.message).toContain('Invalid JWT type');
+    expect(error?.message).toContain('Expected "JWT"');
   });
@@
   it('rejects JWT when headerType array does not include the token type', async () => {
@@
-    const { errors: [error] = [] } = await verifyJwt(jwtWithCustomTyp, inputVerifyJwtOptions);
-    expect(error).toBeDefined();
-    expect(error?.message).toContain('Invalid JWT type');
-    expect(error?.message).toContain('Expected "at+jwt, application/at+jwt"');
+    const { errors: [error] = [] } = await verifyJwt(jwtWithCustomTyp, inputVerifyJwtOptions);
+    expect(error).toBeDefined();
+    expect(error?.reason).toBe('token-invalid');
+    expect(error?.message).toContain('Invalid JWT type');
+    expect(error?.message).toContain('Expected "at+jwt, application/at+jwt"');
   });

This keeps the new headerType behavior well-covered while also locking in the error’s semantic shape.

packages/backend/src/jwt/__tests__/assertions.test.ts (1)

109-150: assertHeaderType tests accurately mirror the new API and error messages

The new describe('assertHeaderType(typ?, allowedTypes?)') block thoroughly exercises:

  • Missing typ with default and custom allowedTypes (no throw).
  • Default behavior for "JWT" vs other values.
  • Single custom allowed type (e.g., 'at+jwt', 'application/at+jwt'), including mismatch cases.
  • Multiple allowed types via array, ensuring both matches and mismatches.
  • Exact error-message formatting (Expected "JWT" and Expected "at+jwt, application/at+jwt"), which matches the implementation that joins allowedTypes with ', '.

This gives strong coverage for the new allowedTypes parameter and its defaulting behavior.

If you want to push edge-case coverage further, you could add a couple of tests for non-string typ values (e.g., null, numbers) to lock in how JSON.stringify(typ) is rendered in the error message. Not necessary for correctness, but would fully document current behavior.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d0d47ba and b54b14a.

📒 Files selected for processing (2)
  • packages/backend/src/jwt/__tests__/assertions.test.ts (1 hunks)
  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{test,spec}.{ts,tsx,js,jsx}: Unit tests are required for all new functionality
Verify proper error handling and edge cases
Include tests for all new features

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.{test,spec,e2e}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use real Clerk instances for integration tests

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/jwt/__tests__/verifyJwt.test.ts
  • packages/backend/src/jwt/__tests__/assertions.test.ts
🧬 Code graph analysis (2)
packages/backend/src/jwt/__tests__/verifyJwt.test.ts (2)
packages/backend/src/fixtures/index.ts (4)
  • mockJwks (73-75)
  • mockJwtPayload (26-34)
  • createJwt (49-60)
  • mockOAuthAccessTokenJwtPayload (36-46)
packages/backend/src/fixtures/machine.ts (2)
  • mockSignedOAuthAccessTokenJwt (73-74)
  • mockSignedOAuthAccessTokenJwtApplicationTyp (80-81)
packages/backend/src/jwt/__tests__/assertions.test.ts (1)
packages/backend/src/jwt/assertions.ts (1)
  • assertHeaderType (50-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Integration Tests (handshake, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Unit Tests (22, shared, clerk-js, RQ)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/backend/src/jwt/__tests__/verifyJwt.test.ts (1)

3-15: New JWT/OAuth fixtures imports are correct and fully utilized

createJwt, mockOAuthAccessTokenJwtPayload, mockSignedOAuthAccessTokenJwt, and mockSignedOAuthAccessTokenJwtApplicationTyp are all used in the new tests and match the intended OAuth access-token JWT scenarios. Import structure and usage look consistent with existing fixture patterns; no issues from ESLint/Prettier or test-design perspectives.

@wobsoriano wobsoriano changed the title feat(backend): Add support for JWTs in OAuth token type feat(backend): [do-not-review] Add support for JWTs in OAuth token type Nov 26, 2025
@wobsoriano wobsoriano changed the title feat(backend): [do-not-review] Add support for JWTs in OAuth token type feat(backend): Add support for JWTs in OAuth token type Nov 26, 2025
@wobsoriano wobsoriano marked this pull request as draft November 26, 2025 03:45
@wobsoriano wobsoriano marked this pull request as ready for review November 26, 2025 06:51
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/backend/src/tokens/machine.ts (2)

18-23: Consider marking OAUTH_ACCESS_TOKEN_TYPES as readonly with as const

Since these are fixed RFC-defined values, you can tighten the type and prevent accidental mutation with a const assertion:

-export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'];
+export const OAUTH_ACCESS_TOKEN_TYPES = ['at+jwt', 'application/at+jwt'] as const;

This also gives you a literal union type for (typeof OAUTH_ACCESS_TOKEN_TYPES)[number], aligning with the guidelines on readonly data and as const.


24-42: isOAuthJwt logic is sound; optional refinement for header.typ type‑guard

The control flow (format check → safe decode with try/catch → header typ membership) correctly identifies RFC 9068 OAuth JWT access tokens without attempting verification here.

For slightly clearer typing and input validation, you could explicitly guard the header type before the includes call:

 export function isOAuthJwt(token: string): boolean {
   if (!isJwtFormat(token)) {
     return false;
   }
   try {
-    const { data, errors } = decodeJwt(token);
-    return !errors && !!data && OAUTH_ACCESS_TOKEN_TYPES.includes(data.header.typ as (typeof OAUTH_ACCESS_TOKEN_TYPES)[number]);
+    const { data, errors } = decodeJwt(token);
+    if (errors || !data) {
+      return false;
+    }
+    const typ = data.header?.typ;
+    if (typeof typ !== 'string') {
+      return false;
+    }
+    return OAUTH_ACCESS_TOKEN_TYPES.includes(typ as (typeof OAUTH_ACCESS_TOKEN_TYPES)[number]);
   } catch {
     return false;
   }
 }

This makes the intent explicit and avoids relying on assertions around data.header.typ.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b54b14a and 9ceae69.

📒 Files selected for processing (2)
  • packages/backend/src/fixtures/index.ts (1 hunks)
  • packages/backend/src/tokens/machine.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/backend/src/fixtures/index.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

All code must pass ESLint checks with the project's configuration

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{js,jsx,ts,tsx,json,md,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Follow established naming conventions (PascalCase for components, camelCase for variables)

Prefer importing types from @clerk/shared/types instead of the deprecated @clerk/types alias

Files:

  • packages/backend/src/tokens/machine.ts
packages/**/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

packages/**/src/**/*.{ts,tsx,js,jsx}: Maintain comprehensive JSDoc comments for public APIs
Use tree-shaking friendly exports
Validate all inputs and sanitize outputs
All public APIs must be documented with JSDoc
Use dynamic imports for optional features
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Implement proper logging with different levels

Files:

  • packages/backend/src/tokens/machine.ts
**/*.ts?(x)

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

Files:

  • packages/backend/src/tokens/machine.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Implement type guards for unknown types using the pattern function isType(value: unknown): value is Type
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details in classes
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Use mixins for shared behavior across unrelated classes in TypeScript
Use generic constraints with bounded type parameters like <T extends { id: string }>
Use utility types like Omit, Partial, and Pick for data transformation instead of manual type construction
Use discriminated unions instead of boolean flags for state management and API responses
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation at the type level
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Document functions with JSDoc comments including @param, @returns, @throws, and @example tags
Create custom error classes that extend Error for specific error types
Use the Result pattern for error handling instead of throwing exceptions
Use optional chaining (?.) and nullish coalescing (??) operators for safe property access
Let TypeScript infer obvious types to reduce verbosity
Use const assertions with as const for literal types
Use satisfies operator for type checking without widening types
Declare readonly arrays and objects for immutable data structures
Use spread operator and array spread for immutable updates instead of mutations
Use lazy loading for large types...

Files:

  • packages/backend/src/tokens/machine.ts
🧬 Code graph analysis (1)
packages/backend/src/tokens/machine.ts (1)
packages/backend/src/jwt/verifyJwt.ts (1)
  • decodeJwt (45-95)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (4)
packages/backend/src/tokens/machine.ts (4)

1-1: Reuse of decodeJwt here is appropriate

Importing decodeJwt directly into this module to inspect the header for classification keeps JWT parsing logic centralized and avoids duplicating decode logic. No issues here.


12-16: JWT format helper looks correct and narrowly scoped

The regexp and isJwtFormat helper correctly implement a quick shape check for three base64url-ish segments before doing a full decode. This is a good, cheap guard in front of decodeJwt.


58-66: Machine token detection now correctly includes OAuth JWTs

Extending isMachineToken to short‑circuit on known prefixes and then fall back to isOAuthJwt is a clean way to treat bare RFC 9068 access tokens as machine tokens while preserving existing prefix behavior. JSDoc is accurate and matches the implementation.


84-84: Mapping OAuth JWTs to TokenType.OAuthToken is consistent with isMachineToken

Including isOAuthJwt(token) in the OAuth branch of getMachineTokenType keeps type resolution aligned with isMachineToken, so prefix‑less OAuth JWTs are consistently classified as oauth_token. This matches the PR objective and looks correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants