Skip to content

feat(tokens): implement path-scoped relayfile tokens#42

Merged
khaliqgant merged 2 commits into
mainfrom
codex/issue-40-path-tokens
May 14, 2026
Merged

feat(tokens): implement path-scoped relayfile tokens#42
khaliqgant merged 2 commits into
mainfrom
codex/issue-40-path-tokens

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

Summary

  • replace the /v1/tokens/path 501 stub with real relay_pa_* path token pair issuance
  • accept workspace tokens through x-api-key and the cloud-compatible Authorization: Bearer relay_ws_* form
  • normalize relayfile path globs, enforce requested path scopes against the workspace token grant, and preserve path-token refresh lineage
  • update SDK/types/tests/docs for the real path token response

Self-review

  • Checked that normal bearer JWT auth remains unchanged: only Bearer relay_ws_* is treated as API-key-backed workspace-token auth.
  • Checked that derived path tokens keep workspaceTokenId metadata, so existing workspace-token revocation checks still close the lineage.
  • Checked that /foo/** normalizes to /foo/*, and arbitrary scopes outside the requested path set are rejected before issuance.

Verification

  • npm --workspace @relayauth/server exec -- node --test --import tsx src/__tests__/tokens-route.test.ts
  • npm --workspace @relayauth/sdk exec -- node --test --import tsx src/__tests__/client-tokens.test.ts
  • npm --workspace @relayauth/server run typecheck
  • npm --workspace @relayauth/sdk run typecheck
  • npm --workspace @relayauth/types run typecheck
  • git diff --check

Closes #40

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Review Change Stack

Warning

Rate limit exceeded

@khaliqgant has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 15 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b2e89ec2-5f15-4154-8b81-1871cbd531a1

📥 Commits

Reviewing files that changed from the base of the PR and between 3380dde and 8339b71.

📒 Files selected for processing (2)
  • packages/server/src/__tests__/api-key-auth-middleware.test.ts
  • packages/server/src/middleware/api-key-auth.ts
📝 Walkthrough

Walkthrough

This PR implements the full /v1/tokens/path endpoint, replacing a 501 "not implemented" stub with complete path-scoped token issuance. The changes span type contracts, token infrastructure, authentication middleware, endpoint logic, refresh handling, SDK integration, and comprehensive tests.

Changes

Path-scoped token issuance implementation

Layer / File(s) Summary
Path token type contracts
packages/types/src/token.ts
PathTokenIssueRequest now accepts optional agent/workspace identifiers with required paths and new ttlSeconds field. PathTokenPair reflects corresponding shape changes with optional agent/workspace metadata. PathTokenStubResponse removed.
Relay token wrapping and prefixes
packages/server/src/lib/jwt.ts
Introduces RELAY_PATH_TOKEN_PREFIX, RelayTokenPrefix type, and wrapRelayToken function for generic prefix-agnostic wrapping. unwrapRelayToken updated to strip either agent or path prefix.
Workspace Bearer token authentication
packages/server/src/middleware/api-key-auth.ts
Updates apiKeyAuth to accept Authorization: Bearer relay_ws_* tokens alongside x-api-key headers; adds extractBearerWorkspaceToken helper to parse and validate Bearer workspace tokens.
Path token issuance endpoint
packages/server/src/routes/tokens.ts (lines 332–414, imports, types)
Fully implements POST /v1/tokens/path: authenticates with relayauth:token:create:*, resolves workspace/agent identities, normalizes paths into relayfile:fs:read/write scopes, enforces scope grants, creates path token identity, issues wrapped token pairs with path metadata, returns PathTokenResponse. Replaces prior 501 stub.
Path token refresh and validation helpers
packages/server/src/routes/tokens.ts (lines 457–495, 667–672, 1067–1292)
Introduces resolveRefreshIdentity to synthesize path token identities from claims; adds isPathClaims and isDerivedClaims for unified claim classification; implements path normalization/validation (normalizePathTokenPaths, normalizePathTokenScopes, etc.) and relay prefix selection helpers; generalizes issueTokenPair wrapping to use dynamic relay token prefixes.
Client SDK integration and exports
packages/sdk/typescript/src/client.ts, packages/sdk/typescript/src/index.ts
Imports and registers PathTokenPair in SDK type registry; corrects RelayAuthClient.issuePathToken signature from Promise<never> to Promise<PathTokenPair>; updates type re-exports to include PathTokenPair and remove PathTokenStubResponse.
Tests and documentation
packages/sdk/typescript/src/__tests__/client-tokens.test.ts, packages/server/src/__tests__/tokens-route.test.ts, README.md
Rewrites path token tests from 501 stub assertions to concrete success/failure cases: validates relay_pa token minting, path normalization, scope expansion, TTL capping, and refresh metadata preservation. Updates JWT decoding to handle relay_pa_ prefixes. Changes out-of-grant path test expectation from 501 to 403 insufficient_scope. Updates endpoint documentation.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AuthMiddleware
  participant TokenRoute
  participant Storage
  participant JWTLib
  Client->>AuthMiddleware: POST /v1/tokens/path with relay_ws_* or x-api-key
  AuthMiddleware->>AuthMiddleware: Extract workspace token from Bearer or x-api-key
  AuthMiddleware->>TokenRoute: Forward authenticated request
  TokenRoute->>TokenRoute: Validate relayauth:token:create:* scope
  TokenRoute->>Storage: Resolve workspace and agent identities
  TokenRoute->>TokenRoute: Normalize paths, expand to relayfile:fs:* scopes
  TokenRoute->>TokenRoute: Validate scopes within workspace token grant
  TokenRoute->>Storage: Create path token identity
  TokenRoute->>JWTLib: Issue access token with path meta + scopes
  TokenRoute->>JWTLib: Issue refresh token with path claims
  JWTLib->>JWTLib: Wrap tokens with relay_pa_ prefix
  TokenRoute->>Client: Return PathTokenResponse with relay_pa_* pair
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A path through the relay, at last takes its form,
With tokens that know where the workspaces swarm,
From stub to solution, the issuance flows bright,
Wrapping relay_pa_ through middleware and light,
The workspace-scoped journey, now fully ignite! 🔑

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(tokens): implement path-scoped relayfile tokens' directly summarizes the main change: implementing the path-scoped token feature that was previously a 501 stub.
Description check ✅ Passed The description clearly relates to the changeset, detailing the replacement of the /v1/tokens/path stub with real implementation, acceptance of workspace tokens via new auth methods, path normalization, and verification steps.
Linked Issues check ✅ Passed The PR successfully implements the full /v1/tokens/path endpoint [#40], replacing the 501 stub with functional path-scoped token issuance, supporting workspace token auth via x-api-key and Bearer relay_ws_* formats, and includes comprehensive updates to SDK, types, and tests.
Out of Scope Changes check ✅ Passed All changes are within scope of implementing path-scoped relayfile tokens: token type definitions, relay prefix utilities, middleware auth enhancements, endpoint implementation, SDK typing, tests, and documentation updates are all directly necessary for the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-40-path-tokens

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

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

}

const [scheme, token] = authorization.split(/\s+/, 2);
if (scheme !== "Bearer" || !token.startsWith(WORKSPACE_TOKEN_PREFIX)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 TypeError crash in extractBearerWorkspaceToken when Authorization header is "Bearer" with no token

When a request includes Authorization: Bearer (with no token value after the scheme), extractBearerWorkspaceToken crashes with a TypeError. At line 52, authorization.split(/\s+/, 2) on the string "Bearer" yields ["Bearer"], so token is undefined. At line 53, scheme !== "Bearer" evaluates to false (scheme IS "Bearer"), so the right side !token.startsWith(WORKSPACE_TOKEN_PREFIX) is evaluated — calling .startsWith() on undefined throws TypeError: Cannot read properties of undefined (reading 'startsWith'). This crashes the apiKeyAuth() middleware, which is mounted on all /v1/tokens/*, /v1/identities/*, and /v1/api-keys/* routes (packages/server/src/server.ts:128-131), making all those endpoints vulnerable to a trivial DoS from any client sending Authorization: Bearer. Note that the analogous authenticate() function in packages/server/src/lib/auth.ts:39 correctly guards against this with !token.

Suggested change
if (scheme !== "Bearer" || !token.startsWith(WORKSPACE_TOKEN_PREFIX)) {
if (scheme !== "Bearer" || !token || !token.startsWith(WORKSPACE_TOKEN_PREFIX)) {
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 8339b71 by guarding !token before startsWith(), with a regression test covering Authorization: Bearer on an apiKeyAuth-mounted route.

@khaliqgant khaliqgant merged commit 9019ded into main May 14, 2026
3 checks passed
@khaliqgant khaliqgant deleted the codex/issue-40-path-tokens branch May 14, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

POST /v1/tokens/path 404s on api.relayauth.dev — stub on main, prod older than v0.2.8

1 participant