feat(cli-auth): add @clerk/cli-auth package#8642
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: c39913e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
| const DEFAULT_SCOPES: OAuthScope[] = ['profile', 'email', 'openid', 'offline_access']; | ||
|
|
||
| function normalizeIssuer(issuer: string): string { | ||
| const normalized = issuer.trim().replace(/\/+$/, ''); |
📝 WalkthroughWalkthroughThis pull request introduces Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| } | ||
|
|
||
| const entry = new keyring.Entry(this.service, this.account(key)); | ||
| return entry.getPassword() ?? (await this.fallback.get(key)); |
There was a problem hiding this comment.
This fallback can return stale file credentials after keychain was the successful write path. set() only writes to keychain when keychain works, but get() falls back to file on null/failure, so an old fallback token can be resurrected. Can we either pick one active backend after probing, or mirror writes/deletes into the fallback so both stores stay coherent?
| async function requestTokens(issuer: string, body: URLSearchParams): Promise<TokenSet> { | ||
| let response: Response; | ||
| try { | ||
| response = await fetch(endpoint(issuer, '/oauth/token'), { |
There was a problem hiding this comment.
This package now has several raw fetch calls without a timeout, here and in verify-api-key.ts. The callback server timeout does not cover token exchange, refresh, revoke, userinfo, or API-key verification, so CLI commands can hang indefinitely. Can we route these through one small internal HTTP helper with an AbortController, shared body parsing, and consistent error mapping?
|
|
||
| async whoami(): Promise<UserInfo | null> { | ||
| const cachedUser = await this.getJson<UserInfo>('user'); | ||
| if (cachedUser) { |
There was a problem hiding this comment.
whoami() returns cached user data before checking whether the stored access token is still fresh or refreshable. That makes identity freshness ambiguous after expiry, revocation, or scope/org changes.
… + timeouts, drop user cache)
…callback type narrows on accepts
…end APIKey + AuthObject types
…oken to take raw tokens
…es.create + correct apiKeys.verify signature
…d stabilize verifier on clerk.authenticateRequest
…drop classifyToken from CLI exports
| } | ||
|
|
||
| function endpoint(issuer: string, path: string): string { | ||
| return `${issuer.replace(/\/+$/, '')}${path}`; |
Summary
Adds
@clerk/cli-authto the monorepo — a package for adding Clerk authentication to Node.js CLIs and the backend routes those CLIs talk to.Ships two entry points:
@clerk/cli-auth— CLI runtime: browser sign-in via PKCE + localhost callback, token storage, refresh, revocation, credential resolution.@clerk/cli-auth/server— backend route handlers for verifying CLI bearers viaclerk.authenticateRequest. Drop into any framework speaking WebRequest/Response(Next.js App Router, Hono, Cloudflare Workers, Bun, Deno).CLI setup
ClerkCliAuthUsage examples
Identity
The SDK provides helper methods for use cases that require resolving identity from an auth token — for example, a
whoamicommand that works with both OAuth and API key auth. All related utilities conform to theIdentityinterface, covering four of Clerk's subject types:cliAuthReturns an instance with helper methods that can be used to resolve auth info and secure endpoints that your CLI communicates with.
Identity resolution handler (for tokens)
The CLI can fetch the authorized party's identity by calling a backend endpoint you host.
For convenience, the SDK exports
handle(), which takes acliAuthinstance and returns a route handler that verifies the bearer token on theAuthorizationheader, resolves the identity of it's subject and responds with a JSONIdentitypayload.Drop into any Fetch API compatible framework (Next.js App Router, Hono, Cloudflare Workers, Bun, Deno).
Don't forget to point
identityEndpoint(in yourClerkCliAuthconfiguration) at this URL to opt-in.Accepted credentials
acceptsvalue'api_key'ak_*Clerk API keys with user, org, or machine subjects'oauth_token'oat_*opaque OAuth access tokens or JWTs'any'For other routes your CLI communicates with use
auth.verifyTokenFromRequest()directly inside your handler:The returned
tokenInfohas subject, type, scopes, and claims — use any of them to authorize the request.Test plan
pnpm test(20 tests, runs offline)pnpm test:integration(16 tests, requiresCLERK_SECRET_KEYandCLERK_PUBLISHABLE_KEY; skips if unset)afterAllpnpm build,pnpm lint,pnpm lint:attw,pnpm lint:publintsuccess