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: c9fbffe 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(/\/+$/, ''); |
| } | ||
|
|
||
| function endpoint(issuer: string, path: string): string { | ||
| return `${issuer.replace(/\/+$/, '')}${path}`; |
📝 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.
Summary
Adds
@clerk/cli-authto the monorepo — an SDK for adding OAuth 2.0 + PKCE localhost-callback authentication to Node.js CLIs that use Clerk.This builds on clerk/cli-auth-example, a reference implementation for the pattern, and promotes it into an official
@clerk/cli-authpackage.From the reference repo (
clerk/cli-auth-example)ClerkCliAuthclass withlogin(),getAccessToken(),whoami(),logout()chmod 0600JSON file, in-memoryexchangeCodeForTokens,refreshAccessToken,fetchUserInfoAdditional changes
API key auth
Added support for Clerk API Key auth alongside OAuth. Verification routes through a consumer-provided backend endpoint where server-side verification (e.g.
clerk.apiKeys.verify(token)) can be used.Token resolution
resolveToken()returns{ token, kind }, giving CLIs the available credential along with its type (oauthorapi_key) so they can route to the right verification path. Checks, in order: (1) a token passed via CLI args, (2) the API key env var named byapiKeys.envVarin the config, (3) the cached OAuth access token. Throws if none are available.Token revocation
logout()now hits/oauth/token/revokeat the issuer by default, so the refresh token is invalidated remotely instead of just being dropped locally. Opt out withlogout({ revoke: false }).Other
UserInfointerfaceOAuthScopetype literal union (user:org:read,public_metadata)