@spfn/auth 0.3.0-beta.17 → 0.3.0-beta.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1592,6 +1592,138 @@ interface OAuthNativeResult {
1592
1592
  */
1593
1593
  declare function oauthNativeService(params: OAuthNativeParams): Promise<OAuthNativeResult>;
1594
1594
 
1595
+ /**
1596
+ * OAuth 2.1 Authorize Service
1597
+ *
1598
+ * The API half of the consent screen. The screen itself is a page on the web
1599
+ * app, because that is where the session cookie is; it has no database, so it
1600
+ * asks here what to draw (`describeOAuth2AuthorizeRequest`) and tells here what
1601
+ * the user decided (`approveOAuth2Authorize` / `denyOAuth2Authorize`). Both
1602
+ * calls validate the request from scratch — the second must never trust what the
1603
+ * first was shown, since a form can be edited between them.
1604
+ *
1605
+ * Refusals come in two kinds and the split is the security property, not a
1606
+ * presentation choice:
1607
+ *
1608
+ * - **Not redirectable.** An unknown `client_id`, or a `redirect_uri` the client
1609
+ * never registered. There is no vetted URI to send the error to, and sending
1610
+ * it to the one the request supplied is precisely the open redirect the
1611
+ * registration check exists to prevent. These are shown on the screen.
1612
+ * - **Redirectable.** Everything else — a missing PKCE challenge, a missing
1613
+ * `resource`, an unknown scope, and the user saying no. The client and its
1614
+ * URI are both vetted by then, so RFC 6749 §4.1.2.1 puts the error back on
1615
+ * that URI as query parameters, which is the only form the waiting CLI can
1616
+ * read.
1617
+ */
1618
+ /** An authorize request as the web handler forwards it, before anything is trusted. */
1619
+ interface OAuth2AuthorizeParams {
1620
+ clientId: string;
1621
+ redirectUri: string;
1622
+ codeChallenge?: string;
1623
+ codeChallengeMethod?: string;
1624
+ resource?: string;
1625
+ scope?: string;
1626
+ state?: string;
1627
+ }
1628
+ /** One scope, with the sentence the consent screen shows for it. */
1629
+ interface OAuth2ScopeDescription {
1630
+ name: string;
1631
+ description: string;
1632
+ }
1633
+ /** Everything the consent screen needs, and nothing it does not. */
1634
+ interface OAuth2ConsentView {
1635
+ clientName: string;
1636
+ /** Host the code would be sent to — the one fact about the client that is checkable. */
1637
+ redirectHost: string;
1638
+ scopes: OAuth2ScopeDescription[];
1639
+ resource: string;
1640
+ }
1641
+ /** What the web handler turns into the success redirect. */
1642
+ interface OAuth2AuthorizationCodeIssued {
1643
+ code: string;
1644
+ /** The presented URI, which matched a registered one. Safe to redirect to. */
1645
+ redirectUri: string;
1646
+ /** Echoed back verbatim, or absent when the request carried none. */
1647
+ state?: string;
1648
+ }
1649
+ /**
1650
+ * What to draw on the consent screen for this request.
1651
+ *
1652
+ * Read-only: nothing is recorded by looking, so a user who closes the tab has
1653
+ * consented to nothing and left nothing behind.
1654
+ */
1655
+ declare function describeOAuth2AuthorizeRequestService(params: OAuth2AuthorizeParams): Promise<OAuth2ConsentView>;
1656
+ /**
1657
+ * Record the consent and mint the code.
1658
+ *
1659
+ * The whole request is validated again rather than carried over from the GET:
1660
+ * the form between the two is in the user's browser, and a parameter changed
1661
+ * there must be caught here and not honoured because the screen once looked
1662
+ * right.
1663
+ *
1664
+ * `userId` comes from the approving session. Never from a request body — that
1665
+ * would be the entire authorization.
1666
+ */
1667
+ declare function approveOAuth2AuthorizeService(params: OAuth2AuthorizeParams, userId: number): Promise<OAuth2AuthorizationCodeIssued>;
1668
+ /**
1669
+ * The user said no.
1670
+ *
1671
+ * Validated first, and validated in full — the same `validate` the approval
1672
+ * runs. `access_denied` goes back to the client on its redirect URI like any
1673
+ * other redirectable error, so the URI has to be one the client registered
1674
+ * before anybody is sent to it; and a request that was malformed was malformed
1675
+ * whichever button was pressed, so answering `access_denied` to it would tell
1676
+ * the waiting client the user refused when in fact it never asked properly.
1677
+ * Nothing is recorded — a refusal is not a grant with a flag on it.
1678
+ */
1679
+ declare function denyOAuth2AuthorizeService(params: OAuth2AuthorizeParams): Promise<never>;
1680
+
1681
+ /**
1682
+ * OAuth 2.1 Grant Service
1683
+ *
1684
+ * The user's side of the authorization server: what is connected, and the button
1685
+ * that disconnects it. A grant is the unit because it is the thing a person can
1686
+ * recognise — "Claude Code, on this API, with these permissions" — and because
1687
+ * revoking it takes every code and token underneath with it.
1688
+ *
1689
+ * `revokeAllOAuth2GrantsForUser` is the same act performed on the user's behalf
1690
+ * rather than by them, and it sits at the four places that revoke everything:
1691
+ * revoke-all, a password change, a completed password reset, a deletion request.
1692
+ * A global revocation that left a grant alive would leave a refresh token alive,
1693
+ * and a CLI holding one would be signed in again within the hour — which is
1694
+ * exactly the device the user was cutting off.
1695
+ */
1696
+ /** One connected client, as the account settings screen lists it. */
1697
+ interface OAuth2GrantSummary {
1698
+ id: number;
1699
+ clientId: string;
1700
+ clientName: string;
1701
+ resource: string;
1702
+ scopes: string[];
1703
+ createdAtMillis: number;
1704
+ lastUsedAtMillis?: number;
1705
+ }
1706
+ /** What a user has connected. Revoked grants are not listed — they are gone. */
1707
+ declare function listOAuth2GrantsService(userId: number): Promise<OAuth2GrantSummary[]>;
1708
+ /**
1709
+ * Disconnect one client.
1710
+ *
1711
+ * The user id is part of the statement's condition, not a check before it: the
1712
+ * id comes from a URL, and a grant belonging to somebody else must answer as if
1713
+ * it did not exist rather than as if it were merely not theirs.
1714
+ */
1715
+ declare function revokeOAuth2GrantService(id: number, userId: number): Promise<void>;
1716
+ /**
1717
+ * Revoke every grant a user has — the authorization-server half of a global
1718
+ * revocation, called beside `deviceAuthorizationsRepository.denyAllActiveByUserId`.
1719
+ *
1720
+ * Tokens are revoked as well as the grants. Verification already refuses a token
1721
+ * whose grant is dead, so this changes no decision; it means a `SELECT` against
1722
+ * `oauth2_tokens` after a revoke-all does not show live-looking rows, which is
1723
+ * the sort of thing that gets read as a hole.
1724
+ */
1725
+ declare function revokeAllOAuth2GrantsForUser(userId: number): Promise<void>;
1726
+
1595
1727
  /**
1596
1728
  * @spfn/auth - Main Router
1597
1729
  *
@@ -1608,6 +1740,7 @@ declare function oauthNativeService(params: OAuthNativeParams): Promise<OAuthNat
1608
1740
  * - Users: /_auth/users/*
1609
1741
  * - Deletion: /_auth/deletion/request, /_auth/deletion/cancel
1610
1742
  * - Admin: /_auth/admin/* (superadmin only)
1743
+ * - OAuth 2.1 authorization server: /_auth/oauth2/*, /.well-known/oauth-authorization-server
1611
1744
  */
1612
1745
  declare const mainAuthRouter: _spfn_core_route.Router<{
1613
1746
  sendVerificationCode: _spfn_core_route.RouteDef<{
@@ -2272,6 +2405,43 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
2272
2405
  createdAt: string | null;
2273
2406
  };
2274
2407
  }>;
2408
+ registerOAuth2Client: _spfn_core_route.RouteDef<{}, {}, Response>;
2409
+ getOAuth2Authorize: _spfn_core_route.RouteDef<{
2410
+ query: _sinclair_typebox.TObject<{
2411
+ client_id: _sinclair_typebox.TString;
2412
+ redirect_uri: _sinclair_typebox.TString;
2413
+ code_challenge: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2414
+ code_challenge_method: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2415
+ resource: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2416
+ scope: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2417
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2418
+ }>;
2419
+ }, {}, OAuth2ConsentView>;
2420
+ createOAuth2AuthorizationCode: _spfn_core_route.RouteDef<{
2421
+ body: _sinclair_typebox.TObject<{
2422
+ approve: _sinclair_typebox.TBoolean;
2423
+ client_id: _sinclair_typebox.TString;
2424
+ redirect_uri: _sinclair_typebox.TString;
2425
+ code_challenge: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2426
+ code_challenge_method: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2427
+ resource: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2428
+ scope: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2429
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
2430
+ }>;
2431
+ }, {}, OAuth2AuthorizationCodeIssued>;
2432
+ oauth2Token: _spfn_core_route.RouteDef<{}, {}, Response>;
2433
+ oauth2Revoke: _spfn_core_route.RouteDef<{}, {}, Response>;
2434
+ listOAuth2Grants: _spfn_core_route.RouteDef<{}, {}, {
2435
+ grants: OAuth2GrantSummary[];
2436
+ }>;
2437
+ revokeOAuth2Grant: _spfn_core_route.RouteDef<{
2438
+ params: _sinclair_typebox.TObject<{
2439
+ id: _sinclair_typebox.TNumber;
2440
+ }>;
2441
+ }, {}, {
2442
+ revoked: boolean;
2443
+ }>;
2444
+ oauth2AuthorizationServerMetadata: _spfn_core_route.RouteDef<{}, {}, Response>;
2275
2445
  }>;
2276
2446
 
2277
2447
  /**
@@ -2566,4 +2736,4 @@ declare const machineAuth: _spfn_core_route.NamedMiddleware<"machineAuth">;
2566
2736
  */
2567
2737
  declare const requireMachineScope: _spfn_core_route.NamedMiddlewareFactory<"machineScope", string[]>;
2568
2738
 
2569
- export { KeyIdSchema as $, type AuthInitOptions as A, type ConfirmPasswordResetParams as B, type ConfirmSignupLinkResult as C, type DeviceAuthInfoResult as D, type ConfirmSignupLinkParams as E, type FinishPasskeyEnrollmentResult as F, type DenyDeviceAuthParams as G, type DeviceAuthApprovedResult as H, type IssueOneTimeTokenResult as I, type DeviceAuthInfoParams as J, type KeySummary as K, type LoginResult as L, type DeviceAuthPendingResult as M, type NewPasskey as N, type OAuthStartResult as O, type PermissionConfig as P, DeviceAuthPollResponseSchema as Q, type RoleConfig as R, type SendVerificationCodeResult as S, DeviceNameSchema as T, type UserProfile as U, VERIFICATION_PURPOSES as V, EmailSchema as W, FingerprintSchema as X, type FinishPasskeyEnrollmentParams as Y, type FinishPasskeyLoginParams as Z, KEY_FINGERPRINT_PREFIX_LENGTH as _, type RegisterResult as a, issueOneTimeTokenService as a$, type LoginParams as a0, type LogoutParams as a1, type MachinePrincipal as a2, type MachineVerifierRegistration as a3, type NativeVerifyOptions as a4, type NormalizedIdentity as a5, type OAuthCallbackParams as a6, type OAuthCallbackResult as a7, type OAuthCodeExchangeOptions as a8, type OAuthNativeParams as a9, UnlinkNotifyRejection as aA, type UnlinkNotifyRequest as aB, type UnlinkNotifyResult as aC, UserCodeSchema as aD, VerificationPurposeSchema as aE, type VerifyCodeParams as aF, type VerifyCodeResult as aG, approveDeviceAuthService as aH, assertNotLastRecoveryCredential as aI, assertRecentAuthentication as aJ, authenticate as aK, buildOAuthErrorUrl as aL, changePasswordService as aM, completePasswordResetService as aN, completeSignupService as aO, confirmPasswordResetService as aP, confirmSignupLinkService as aQ, denyDeviceAuthService as aR, finishPasskeyEnrollmentService as aS, finishPasskeyLoginService as aT, getDeviceAuthInfoService as aU, getEnabledOAuthProviders as aV, getGoogleAccessToken as aW, getMachinePrincipal as aX, getOAuthProvider as aY, getRegisteredProviders as aZ, isOAuthProviderEnabled as a_, type OAuthStartParams as aa, type OAuthTokens as ab, PASSKEY_DEVICE_TYPES as ac, PASSKEY_LABEL_MAX_LENGTH as ad, type PasskeyDeviceType as ae, PasswordSchema as af, PhoneSchema as ag, PlatformSchema as ah, type PollDeviceAuthParams as ai, type PollDeviceAuthResult as aj, PublicKeySchema as ak, type RecentAuthenticationParams as al, type RegisterParams as am, type RegisterPublicKeyParams as an, type RenamePasskeyParams as ao, type RequestPasswordResetParams as ap, type RequestSignupLinkParams as aq, type RevokeAllKeysParams as ar, type RevokeKeyParams as as, type RevokePasskeyParams as at, type RotateKeyParams as au, type SendVerificationCodeParams as av, type StartDeviceAuthParams as aw, type StartPasskeyEnrollmentParams as ax, TargetTypeSchema as ay, type UnlinkNotification as az, type RequestSignupLinkResult as b, listKeysService as b0, listPasskeysService as b1, loginService as b2, logoutService as b3, machineAuth as b4, oauthCallbackService as b5, oauthNativeService as b6, oauthStartService as b7, oauthUnlinkNotifyService as b8, optionalAuth as b9, passkeys as ba, pollDeviceAuthService as bb, registerAuthProfile as bc, registerMachineVerifier as bd, registerOAuthProvider as be, registerPublicKeyService as bf, registerService as bg, renamePasskeyService as bh, requestPasswordResetService as bi, requestSignupLinkService as bj, requireEnabledProvider as bk, requireMachineScope as bl, resolveAuthenticatedUser as bm, revokeAllKeysService as bn, revokeKeyService as bo, revokePasskeyService as bp, rotateKeyService as bq, runAuthProfile as br, selectAuthProfile as bs, sendVerificationCodeService as bt, startDeviceAuthService as bu, startPasskeyEnrollmentService as bv, startPasskeyLoginService as bw, verifyCodeService as bx, verifyOneTimeTokenService as by, type RequestPasswordResetResult as c, type ConfirmPasswordResetResult as d, type StartDeviceAuthResult as e, type PasskeySummary as f, type RotateKeyResult as g, type RevokeAllKeysResult as h, type OAuthNativeResult as i, type ProfileInfo as j, type AuthSession as k, PERMISSION_CATEGORIES as l, mainAuthRouter as m, type PermissionCategory as n, VERIFICATION_TARGET_TYPES as o, type VerificationPurpose as p, type VerificationTargetType as q, type OAuthProvider as r, type Passkey as s, type AuthContext as t, type ApproveDeviceAuthParams as u, type AuthProfileOutcome as v, type AuthProfileVerifier as w, type ChangePasswordParams as x, type CompletePasswordResetParams as y, type CompleteSignupParams as z };
2739
+ export { type FinishPasskeyEnrollmentParams as $, type AuthInitOptions as A, type ChangePasswordParams as B, type ConfirmSignupLinkResult as C, type DeviceAuthInfoResult as D, type CompletePasswordResetParams as E, type FinishPasskeyEnrollmentResult as F, type CompleteSignupParams as G, type ConfirmPasswordResetParams as H, type IssueOneTimeTokenResult as I, type ConfirmSignupLinkParams as J, type KeySummary as K, type LoginResult as L, type DenyDeviceAuthParams as M, type NewPasskey as N, type OAuthStartResult as O, type PermissionConfig as P, type DeviceAuthApprovedResult as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type DeviceAuthInfoParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type DeviceAuthPendingResult as W, DeviceAuthPollResponseSchema as X, DeviceNameSchema as Y, EmailSchema as Z, FingerprintSchema as _, type RegisterResult as a, finishPasskeyLoginService as a$, type FinishPasskeyLoginParams as a0, KEY_FINGERPRINT_PREFIX_LENGTH as a1, KeyIdSchema as a2, type LoginParams as a3, type LogoutParams as a4, type MachinePrincipal as a5, type MachineVerifierRegistration as a6, type NativeVerifyOptions as a7, type NormalizedIdentity as a8, type OAuth2AuthorizeParams as a9, type SendVerificationCodeParams as aA, type StartDeviceAuthParams as aB, type StartPasskeyEnrollmentParams as aC, TargetTypeSchema as aD, type UnlinkNotification as aE, UnlinkNotifyRejection as aF, type UnlinkNotifyRequest as aG, type UnlinkNotifyResult as aH, UserCodeSchema as aI, VerificationPurposeSchema as aJ, type VerifyCodeParams as aK, type VerifyCodeResult as aL, approveDeviceAuthService as aM, approveOAuth2AuthorizeService as aN, assertNotLastRecoveryCredential as aO, assertRecentAuthentication as aP, authenticate as aQ, buildOAuthErrorUrl as aR, changePasswordService as aS, completePasswordResetService as aT, completeSignupService as aU, confirmPasswordResetService as aV, confirmSignupLinkService as aW, denyDeviceAuthService as aX, denyOAuth2AuthorizeService as aY, describeOAuth2AuthorizeRequestService as aZ, finishPasskeyEnrollmentService as a_, type OAuth2ScopeDescription as aa, type OAuthCallbackParams as ab, type OAuthCallbackResult as ac, type OAuthCodeExchangeOptions as ad, type OAuthNativeParams as ae, type OAuthStartParams as af, type OAuthTokens as ag, PASSKEY_DEVICE_TYPES as ah, PASSKEY_LABEL_MAX_LENGTH as ai, type PasskeyDeviceType as aj, PasswordSchema as ak, PhoneSchema as al, PlatformSchema as am, type PollDeviceAuthParams as an, type PollDeviceAuthResult as ao, PublicKeySchema as ap, type RecentAuthenticationParams as aq, type RegisterParams as ar, type RegisterPublicKeyParams as as, type RenamePasskeyParams as at, type RequestPasswordResetParams as au, type RequestSignupLinkParams as av, type RevokeAllKeysParams as aw, type RevokeKeyParams as ax, type RevokePasskeyParams as ay, type RotateKeyParams as az, type RequestSignupLinkResult as b, getDeviceAuthInfoService as b0, getEnabledOAuthProviders as b1, getGoogleAccessToken as b2, getMachinePrincipal as b3, getOAuthProvider as b4, getRegisteredProviders as b5, isOAuthProviderEnabled as b6, issueOneTimeTokenService as b7, listKeysService as b8, listOAuth2GrantsService as b9, revokePasskeyService as bA, rotateKeyService as bB, runAuthProfile as bC, selectAuthProfile as bD, sendVerificationCodeService as bE, startDeviceAuthService as bF, startPasskeyEnrollmentService as bG, startPasskeyLoginService as bH, verifyCodeService as bI, verifyOneTimeTokenService as bJ, listPasskeysService as ba, loginService as bb, logoutService as bc, machineAuth as bd, oauthCallbackService as be, oauthNativeService as bf, oauthStartService as bg, oauthUnlinkNotifyService as bh, optionalAuth as bi, passkeys as bj, pollDeviceAuthService as bk, registerAuthProfile as bl, registerMachineVerifier as bm, registerOAuthProvider as bn, registerPublicKeyService as bo, registerService as bp, renamePasskeyService as bq, requestPasswordResetService as br, requestSignupLinkService as bs, requireEnabledProvider as bt, requireMachineScope as bu, resolveAuthenticatedUser as bv, revokeAllKeysService as bw, revokeAllOAuth2GrantsForUser as bx, revokeKeyService as by, revokeOAuth2GrantService as bz, type RequestPasswordResetResult as c, type ConfirmPasswordResetResult as d, type StartDeviceAuthResult as e, type PasskeySummary as f, type RotateKeyResult as g, type RevokeAllKeysResult as h, type OAuthNativeResult as i, type ProfileInfo as j, type OAuth2ConsentView as k, type OAuth2AuthorizationCodeIssued as l, mainAuthRouter as m, type OAuth2GrantSummary as n, type AuthSession as o, PERMISSION_CATEGORIES as p, type PermissionCategory as q, VERIFICATION_TARGET_TYPES as r, type VerificationPurpose as s, type VerificationTargetType as t, type OAuthProvider as u, type Passkey as v, type AuthContext as w, type ApproveDeviceAuthParams as x, type AuthProfileOutcome as y, type AuthProfileVerifier as z };
@@ -285,8 +285,13 @@ function getCsrfMode() {
285
285
  }
286
286
  return normalized;
287
287
  }
288
+ var PACKAGE_CSRF_EXEMPT_PATHS = [
289
+ "/_auth/oauth2/register",
290
+ "/_auth/oauth2/token",
291
+ "/_auth/oauth2/revoke"
292
+ ];
288
293
  function getCsrfExemptPaths() {
289
- return globalConfig.csrf?.exemptPaths ?? [];
294
+ return [...PACKAGE_CSRF_EXEMPT_PATHS, ...globalConfig.csrf?.exemptPaths ?? []];
290
295
  }
291
296
 
292
297
  // src/nextjs/interceptors/cookie-options.ts