@productcraft/auth 0.7.1 → 0.8.0

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.
package/dist/index.d.cts CHANGED
@@ -2823,9 +2823,18 @@ interface VerifyOptions {
2823
2823
  /** Maximum token age — passed straight to jose. */
2824
2824
  maxTokenAge?: string | number;
2825
2825
  }
2826
+ /**
2827
+ * True when the claims mark a refresh token: `token_use: "refresh"`
2828
+ * (current shape) or `type: "refresh"` (older Auth tokens). Refresh
2829
+ * tokens must never authenticate a request.
2830
+ */
2831
+ declare function isRefreshToken(claims: Record<string, unknown> | null | undefined): boolean;
2826
2832
  /**
2827
2833
  * Verify an Auth-issued JWT against a JWKS resolver.
2828
2834
  *
2835
+ * Refresh tokens are refused with `JwtRefreshTokenError` even when the
2836
+ * signature, issuer and audience are valid.
2837
+ *
2829
2838
  * @param token The compact-form JWT (header.payload.signature)
2830
2839
  * @param getKey A jose-compatible key resolver — pass
2831
2840
  * `scope.jwks.getKey` from a `ConsumerScope`
@@ -3236,6 +3245,16 @@ declare class JwtNotYetValidError extends JwtVerifyError {
3236
3245
  cause?: unknown;
3237
3246
  });
3238
3247
  }
3248
+ /**
3249
+ * The token is a refresh token (`token_use: "refresh"` or
3250
+ * `type: "refresh"`). Refresh tokens are only valid at the refresh
3251
+ * endpoint and must never authenticate an API request.
3252
+ */
3253
+ declare class JwtRefreshTokenError extends JwtVerifyError {
3254
+ constructor(message?: string, options?: {
3255
+ cause?: unknown;
3256
+ });
3257
+ }
3239
3258
  /** `iss` claim doesn't match the expected issuer. */
3240
3259
  declare class JwtIssuerMismatchError extends JwtVerifyError {
3241
3260
  constructor(message: string, options?: {
@@ -3286,7 +3305,15 @@ interface AuthConfig extends PCClientConfig {
3286
3305
  jwksTtlMs?: number;
3287
3306
  }
3288
3307
  declare class Auth {
3308
+ /** Admin client: explicit `auth`, else `PRODUCTCRAFT_API_KEY`. */
3289
3309
  private readonly client;
3310
+ /**
3311
+ * Consumer client: explicit `auth` only. Consumer routes act for an
3312
+ * end user, so a workspace key from the environment must never leak
3313
+ * onto them. Pass `auth` explicitly for PAK-only consumer routes
3314
+ * (`signup_requires_pak`, tenants, code mint, factors).
3315
+ */
3316
+ private readonly consumerClient;
3290
3317
  private readonly baseUrl;
3291
3318
  private readonly fetch;
3292
3319
  private readonly jwtConfig;
@@ -3294,15 +3321,20 @@ declare class Auth {
3294
3321
  /**
3295
3322
  * Returns an `AppScope` bound to the given appId. All operations under
3296
3323
  * `/v1/apps/{appId}/...` are exposed as resource namespaces on the
3297
- * returned object.
3324
+ * returned object. Uses the explicit `auth`, else
3325
+ * `PRODUCTCRAFT_API_KEY` from the environment.
3298
3326
  */
3299
3327
  app(appId: string): AppScope;
3300
3328
  /**
3301
3329
  * Returns a `ConsumerScope` bound to the given appSlug. Exposes the
3302
3330
  * `/{appSlug}/v1/...` surface (sign-in, sign-up, me, verify, oauth)
3303
3331
  * and the JWT-verify helper for tokens issued by this app.
3332
+ *
3333
+ * `appSlug` defaults to `PRODUCTCRAFT_AUTH_APP` from the environment.
3334
+ * No credential is ever read from the environment for consumer
3335
+ * routes; only an explicit `auth` is sent.
3304
3336
  */
3305
- consumer(appSlug: string): ConsumerScope;
3337
+ consumer(appSlug?: string): ConsumerScope;
3306
3338
  readonly apps: {
3307
3339
  /** List apps the caller's workspace can see. */
3308
3340
  list: (params?: Partial<AppControllerListMyAppsQueryParams>) => Promise<AppListResponseDto>;
@@ -3319,4 +3351,4 @@ declare class Auth {
3319
3351
  };
3320
3352
  }
3321
3353
 
3322
- export { AUTH_LEGACY_ISSUER, AppScope, type AssignRoleDto, Auth, type AuthClaims, type AuthConfig, AuthHttpError, type AuthorizeBatchBody, type AuthorizeBody, type ClientCredentialsDto, type ConfirmEnrollmentResponseDto, type ConsumerAcceptInviteDto, type ConsumerLogoutDto, type ConsumerRefreshDto, type ConsumerRequestPasswordResetDto, type ConsumerResetPasswordDto, ConsumerScope, type ConsumerSigninDto, type ConsumerSignupDto, type ConsumerTokenResponseDto, type CreateApiKeyDto, type CreateAppDto, type CreateEndUserInviteDto, type CreateM2MClientDto, type CreatePermissionDto, type CreateRoleDto, type EncodedPasskeyCredential, type EndUserInviteResponseDto, type IdpNativeSigninDto, type IdpNativeUserHintDto, type IdpTokenResponseDto, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtVerifyError, type PasskeyBrowserOptions, type PasskeyCredentialLike, type PasskeyCredentialsContainer, type PasskeyDecodedOptions, PasskeyError, type PasskeyErrorCode, type PasskeyMediation, type PasskeyPublicKeyOptions, type PublicFactorDto, type SetPermissionsDto, type SetScopesDto, type StepUpResponseDto, type UpdateAppDto, type UpdateAppStatusDto, type UpdateAuthConfigDto, type UpdateEndUserDto, type UpdateEndUserRoleDto, type UpdateEndUserStatusDto, type UpdateM2MClientDto, type UpdateMeDto, type UpdateRoleDto, type VerifyBody, type VerifyOptions, type WebauthnCredentialDto, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, toB64u, verifyAuthToken };
3354
+ export { AUTH_LEGACY_ISSUER, AppScope, type AssignRoleDto, Auth, type AuthClaims, type AuthConfig, AuthHttpError, type AuthorizeBatchBody, type AuthorizeBody, type ClientCredentialsDto, type ConfirmEnrollmentResponseDto, type ConsumerAcceptInviteDto, type ConsumerLogoutDto, type ConsumerRefreshDto, type ConsumerRequestPasswordResetDto, type ConsumerResetPasswordDto, ConsumerScope, type ConsumerSigninDto, type ConsumerSignupDto, type ConsumerTokenResponseDto, type CreateApiKeyDto, type CreateAppDto, type CreateEndUserInviteDto, type CreateM2MClientDto, type CreatePermissionDto, type CreateRoleDto, type EncodedPasskeyCredential, type EndUserInviteResponseDto, type IdpNativeSigninDto, type IdpNativeUserHintDto, type IdpTokenResponseDto, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtRefreshTokenError, JwtVerifyError, type PasskeyBrowserOptions, type PasskeyCredentialLike, type PasskeyCredentialsContainer, type PasskeyDecodedOptions, PasskeyError, type PasskeyErrorCode, type PasskeyMediation, type PasskeyPublicKeyOptions, type PublicFactorDto, type SetPermissionsDto, type SetScopesDto, type StepUpResponseDto, type UpdateAppDto, type UpdateAppStatusDto, type UpdateAuthConfigDto, type UpdateEndUserDto, type UpdateEndUserRoleDto, type UpdateEndUserStatusDto, type UpdateM2MClientDto, type UpdateMeDto, type UpdateRoleDto, type VerifyBody, type VerifyOptions, type WebauthnCredentialDto, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, isRefreshToken, toB64u, verifyAuthToken };
package/dist/index.d.ts CHANGED
@@ -2823,9 +2823,18 @@ interface VerifyOptions {
2823
2823
  /** Maximum token age — passed straight to jose. */
2824
2824
  maxTokenAge?: string | number;
2825
2825
  }
2826
+ /**
2827
+ * True when the claims mark a refresh token: `token_use: "refresh"`
2828
+ * (current shape) or `type: "refresh"` (older Auth tokens). Refresh
2829
+ * tokens must never authenticate a request.
2830
+ */
2831
+ declare function isRefreshToken(claims: Record<string, unknown> | null | undefined): boolean;
2826
2832
  /**
2827
2833
  * Verify an Auth-issued JWT against a JWKS resolver.
2828
2834
  *
2835
+ * Refresh tokens are refused with `JwtRefreshTokenError` even when the
2836
+ * signature, issuer and audience are valid.
2837
+ *
2829
2838
  * @param token The compact-form JWT (header.payload.signature)
2830
2839
  * @param getKey A jose-compatible key resolver — pass
2831
2840
  * `scope.jwks.getKey` from a `ConsumerScope`
@@ -3236,6 +3245,16 @@ declare class JwtNotYetValidError extends JwtVerifyError {
3236
3245
  cause?: unknown;
3237
3246
  });
3238
3247
  }
3248
+ /**
3249
+ * The token is a refresh token (`token_use: "refresh"` or
3250
+ * `type: "refresh"`). Refresh tokens are only valid at the refresh
3251
+ * endpoint and must never authenticate an API request.
3252
+ */
3253
+ declare class JwtRefreshTokenError extends JwtVerifyError {
3254
+ constructor(message?: string, options?: {
3255
+ cause?: unknown;
3256
+ });
3257
+ }
3239
3258
  /** `iss` claim doesn't match the expected issuer. */
3240
3259
  declare class JwtIssuerMismatchError extends JwtVerifyError {
3241
3260
  constructor(message: string, options?: {
@@ -3286,7 +3305,15 @@ interface AuthConfig extends PCClientConfig {
3286
3305
  jwksTtlMs?: number;
3287
3306
  }
3288
3307
  declare class Auth {
3308
+ /** Admin client: explicit `auth`, else `PRODUCTCRAFT_API_KEY`. */
3289
3309
  private readonly client;
3310
+ /**
3311
+ * Consumer client: explicit `auth` only. Consumer routes act for an
3312
+ * end user, so a workspace key from the environment must never leak
3313
+ * onto them. Pass `auth` explicitly for PAK-only consumer routes
3314
+ * (`signup_requires_pak`, tenants, code mint, factors).
3315
+ */
3316
+ private readonly consumerClient;
3290
3317
  private readonly baseUrl;
3291
3318
  private readonly fetch;
3292
3319
  private readonly jwtConfig;
@@ -3294,15 +3321,20 @@ declare class Auth {
3294
3321
  /**
3295
3322
  * Returns an `AppScope` bound to the given appId. All operations under
3296
3323
  * `/v1/apps/{appId}/...` are exposed as resource namespaces on the
3297
- * returned object.
3324
+ * returned object. Uses the explicit `auth`, else
3325
+ * `PRODUCTCRAFT_API_KEY` from the environment.
3298
3326
  */
3299
3327
  app(appId: string): AppScope;
3300
3328
  /**
3301
3329
  * Returns a `ConsumerScope` bound to the given appSlug. Exposes the
3302
3330
  * `/{appSlug}/v1/...` surface (sign-in, sign-up, me, verify, oauth)
3303
3331
  * and the JWT-verify helper for tokens issued by this app.
3332
+ *
3333
+ * `appSlug` defaults to `PRODUCTCRAFT_AUTH_APP` from the environment.
3334
+ * No credential is ever read from the environment for consumer
3335
+ * routes; only an explicit `auth` is sent.
3304
3336
  */
3305
- consumer(appSlug: string): ConsumerScope;
3337
+ consumer(appSlug?: string): ConsumerScope;
3306
3338
  readonly apps: {
3307
3339
  /** List apps the caller's workspace can see. */
3308
3340
  list: (params?: Partial<AppControllerListMyAppsQueryParams>) => Promise<AppListResponseDto>;
@@ -3319,4 +3351,4 @@ declare class Auth {
3319
3351
  };
3320
3352
  }
3321
3353
 
3322
- export { AUTH_LEGACY_ISSUER, AppScope, type AssignRoleDto, Auth, type AuthClaims, type AuthConfig, AuthHttpError, type AuthorizeBatchBody, type AuthorizeBody, type ClientCredentialsDto, type ConfirmEnrollmentResponseDto, type ConsumerAcceptInviteDto, type ConsumerLogoutDto, type ConsumerRefreshDto, type ConsumerRequestPasswordResetDto, type ConsumerResetPasswordDto, ConsumerScope, type ConsumerSigninDto, type ConsumerSignupDto, type ConsumerTokenResponseDto, type CreateApiKeyDto, type CreateAppDto, type CreateEndUserInviteDto, type CreateM2MClientDto, type CreatePermissionDto, type CreateRoleDto, type EncodedPasskeyCredential, type EndUserInviteResponseDto, type IdpNativeSigninDto, type IdpNativeUserHintDto, type IdpTokenResponseDto, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtVerifyError, type PasskeyBrowserOptions, type PasskeyCredentialLike, type PasskeyCredentialsContainer, type PasskeyDecodedOptions, PasskeyError, type PasskeyErrorCode, type PasskeyMediation, type PasskeyPublicKeyOptions, type PublicFactorDto, type SetPermissionsDto, type SetScopesDto, type StepUpResponseDto, type UpdateAppDto, type UpdateAppStatusDto, type UpdateAuthConfigDto, type UpdateEndUserDto, type UpdateEndUserRoleDto, type UpdateEndUserStatusDto, type UpdateM2MClientDto, type UpdateMeDto, type UpdateRoleDto, type VerifyBody, type VerifyOptions, type WebauthnCredentialDto, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, toB64u, verifyAuthToken };
3354
+ export { AUTH_LEGACY_ISSUER, AppScope, type AssignRoleDto, Auth, type AuthClaims, type AuthConfig, AuthHttpError, type AuthorizeBatchBody, type AuthorizeBody, type ClientCredentialsDto, type ConfirmEnrollmentResponseDto, type ConsumerAcceptInviteDto, type ConsumerLogoutDto, type ConsumerRefreshDto, type ConsumerRequestPasswordResetDto, type ConsumerResetPasswordDto, ConsumerScope, type ConsumerSigninDto, type ConsumerSignupDto, type ConsumerTokenResponseDto, type CreateApiKeyDto, type CreateAppDto, type CreateEndUserInviteDto, type CreateM2MClientDto, type CreatePermissionDto, type CreateRoleDto, type EncodedPasskeyCredential, type EndUserInviteResponseDto, type IdpNativeSigninDto, type IdpNativeUserHintDto, type IdpTokenResponseDto, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtRefreshTokenError, JwtVerifyError, type PasskeyBrowserOptions, type PasskeyCredentialLike, type PasskeyCredentialsContainer, type PasskeyDecodedOptions, PasskeyError, type PasskeyErrorCode, type PasskeyMediation, type PasskeyPublicKeyOptions, type PublicFactorDto, type SetPermissionsDto, type SetScopesDto, type StepUpResponseDto, type UpdateAppDto, type UpdateAppStatusDto, type UpdateAuthConfigDto, type UpdateEndUserDto, type UpdateEndUserRoleDto, type UpdateEndUserStatusDto, type UpdateM2MClientDto, type UpdateMeDto, type UpdateRoleDto, type VerifyBody, type VerifyOptions, type WebauthnCredentialDto, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, isRefreshToken, toB64u, verifyAuthToken };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { PC_BASE_URL } from '@productcraft/core';
1
+ import { PC_BASE_URL, resolveAuth, readEnv, PC_AUTH_APP_ENV } from '@productcraft/core';
2
2
  import { createRemoteJWKSet, errors, jwtVerify, customFetch } from 'jose';
3
3
 
4
4
  // src/index.ts
@@ -2068,6 +2068,12 @@ var JwtNotYetValidError = class extends JwtVerifyError {
2068
2068
  this.name = "JwtNotYetValidError";
2069
2069
  }
2070
2070
  };
2071
+ var JwtRefreshTokenError = class extends JwtVerifyError {
2072
+ constructor(message = "Refresh tokens cannot be used as access tokens", options) {
2073
+ super("ERR_JWT_REFRESH_TOKEN", message, options);
2074
+ this.name = "JwtRefreshTokenError";
2075
+ }
2076
+ };
2071
2077
  var JwtIssuerMismatchError = class extends JwtVerifyError {
2072
2078
  constructor(message, options) {
2073
2079
  super("ERR_JWT_ISS_MISMATCH", message, options);
@@ -2148,6 +2154,10 @@ var JwksCache = class {
2148
2154
  refresh() {
2149
2155
  }
2150
2156
  };
2157
+ function isRefreshToken(claims) {
2158
+ if (!claims) return false;
2159
+ return claims.token_use === "refresh" || claims.type === "refresh";
2160
+ }
2151
2161
  async function verifyAuthToken(token, getKey, opts = {}) {
2152
2162
  try {
2153
2163
  const { payload } = await jwtVerify(token, getKey, {
@@ -2159,6 +2169,7 @@ async function verifyAuthToken(token, getKey, opts = {}) {
2159
2169
  currentDate: opts.currentDate,
2160
2170
  maxTokenAge: opts.maxTokenAge
2161
2171
  });
2172
+ if (isRefreshToken(payload)) throw new JwtRefreshTokenError();
2162
2173
  return payload;
2163
2174
  } catch (err) {
2164
2175
  throw translateJoseError(err);
@@ -2700,7 +2711,15 @@ async function statsControllerGetMyStats({ params } = {}, config = {}) {
2700
2711
 
2701
2712
  // src/index.ts
2702
2713
  var Auth = class {
2714
+ /** Admin client: explicit `auth`, else `PRODUCTCRAFT_API_KEY`. */
2703
2715
  client;
2716
+ /**
2717
+ * Consumer client: explicit `auth` only. Consumer routes act for an
2718
+ * end user, so a workspace key from the environment must never leak
2719
+ * onto them. Pass `auth` explicitly for PAK-only consumer routes
2720
+ * (`signup_requires_pak`, tenants, code mint, factors).
2721
+ */
2722
+ consumerClient;
2704
2723
  baseUrl;
2705
2724
  fetch;
2706
2725
  jwtConfig;
@@ -2708,6 +2727,11 @@ var Auth = class {
2708
2727
  this.baseUrl = config.baseUrl ?? PC_BASE_URL.auth;
2709
2728
  this.fetch = config.fetch;
2710
2729
  this.client = makeAuthHttpClient({
2730
+ baseUrl: this.baseUrl,
2731
+ auth: resolveAuth(config.auth),
2732
+ fetch: this.fetch
2733
+ });
2734
+ this.consumerClient = makeAuthHttpClient({
2711
2735
  baseUrl: this.baseUrl,
2712
2736
  auth: config.auth,
2713
2737
  fetch: this.fetch
@@ -2719,7 +2743,8 @@ var Auth = class {
2719
2743
  /**
2720
2744
  * Returns an `AppScope` bound to the given appId. All operations under
2721
2745
  * `/v1/apps/{appId}/...` are exposed as resource namespaces on the
2722
- * returned object.
2746
+ * returned object. Uses the explicit `auth`, else
2747
+ * `PRODUCTCRAFT_API_KEY` from the environment.
2723
2748
  */
2724
2749
  app(appId) {
2725
2750
  return new AppScope(appId, this.client);
@@ -2728,11 +2753,21 @@ var Auth = class {
2728
2753
  * Returns a `ConsumerScope` bound to the given appSlug. Exposes the
2729
2754
  * `/{appSlug}/v1/...` surface (sign-in, sign-up, me, verify, oauth)
2730
2755
  * and the JWT-verify helper for tokens issued by this app.
2756
+ *
2757
+ * `appSlug` defaults to `PRODUCTCRAFT_AUTH_APP` from the environment.
2758
+ * No credential is ever read from the environment for consumer
2759
+ * routes; only an explicit `auth` is sent.
2731
2760
  */
2732
2761
  consumer(appSlug) {
2762
+ const slug = appSlug ?? readEnv(PC_AUTH_APP_ENV);
2763
+ if (!slug) {
2764
+ throw new Error(
2765
+ `@productcraft/auth: consumer() needs an app slug. Pass one, or set ${PC_AUTH_APP_ENV}.`
2766
+ );
2767
+ }
2733
2768
  return new ConsumerScope(
2734
- appSlug,
2735
- { client: this.client, baseUrl: this.baseUrl, fetch: this.fetch },
2769
+ slug,
2770
+ { client: this.consumerClient, baseUrl: this.baseUrl, fetch: this.fetch },
2736
2771
  this.jwtConfig
2737
2772
  );
2738
2773
  }
@@ -2771,6 +2806,6 @@ var Auth = class {
2771
2806
  };
2772
2807
  };
2773
2808
 
2774
- export { AUTH_LEGACY_ISSUER, AppScope, Auth, AuthHttpError, ConsumerScope, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtVerifyError, PasskeyError, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, toB64u, verifyAuthToken };
2809
+ export { AUTH_LEGACY_ISSUER, AppScope, Auth, AuthHttpError, ConsumerScope, JwksCache, JwksFetchError, JwksKeyNotFoundError, JwtAudienceMismatchError, JwtExpiredError, JwtInvalidError, JwtIssuerMismatchError, JwtNotYetValidError, JwtRefreshTokenError, JwtVerifyError, PasskeyError, createPasskeyCredential, decodeOptions, encodeCredential, fromB64u, getPasskeyCredential, isPasskeySupported, isRefreshToken, toB64u, verifyAuthToken };
2775
2810
  //# sourceMappingURL=index.js.map
2776
2811
  //# sourceMappingURL=index.js.map