nuxt-auth-utils 0.6.1 → 0.6.2

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/README.md CHANGED
@@ -410,6 +410,38 @@ export default defineNuxtConfig({
410
410
  })
411
411
  ```
412
412
 
413
+ #### Callback path
414
+
415
+ The authorization server compares the redirect URI of the login request with the list published in the client metadata document. That document is served from `bluesky/client-metadata.json` under your app base URL (`app.baseURL`, `/` by default), so it cannot know where your login route lives.
416
+
417
+ The module fills in `/auth/<provider>`, the path its playground uses, under that base URL. The login route is served under the base URL too, so a deployment that sets `app.baseURL` publishes the path its login route answers on:
418
+
419
+ ```text
420
+ app.baseURL: '/my-app/' -> redirect_uris: ["https://example.com/my-app/auth/bluesky"]
421
+ ```
422
+
423
+ Set `redirectUris` when your login route lives elsewhere; until you do, the module logs a warning in development. Both requests then use it:
424
+
425
+ ```ts
426
+ export default defineNuxtConfig({
427
+ runtimeConfig: {
428
+ oauth: {
429
+ bluesky: {
430
+ redirectUris: ['/login/bluesky']
431
+ }
432
+ }
433
+ }
434
+ })
435
+ ```
436
+
437
+ Declare paths only, without the origin or the app base URL. The module prepends the base URL, like it does for `/auth/<provider>`, and leaves a path that already starts with it as is. It then prepends the origin of the request, because the URL origin must match the client ID:
438
+
439
+ ```text
440
+ app.baseURL: '/my-app/', redirectUris: ['/login/bluesky'] -> redirect_uris: ["https://example.com/my-app/login/bluesky"]
441
+ ```
442
+
443
+ The `redirectUrl` option of `defineOAuthBlueskyEventHandler()` applies to the login request alone, also under the base URL. The metadata document cannot see it, so use `redirectUris` for a custom callback path.
444
+
413
445
  ### WebAuthn (passkey)
414
446
 
415
447
  WebAuthn (Web Authentication) is a web standard that enhances security by replacing passwords with passkeys using public key cryptography. Users can authenticate with biometric data (like fingerprints or facial recognition) or physical devices (like USB keys), reducing the risk of phishing and password breaches. This approach offers a more secure and user-friendly authentication method, supported by major browsers and platforms.
@@ -432,6 +464,37 @@ export default defineNuxtConfig({
432
464
  })
433
465
  ```
434
466
 
467
+ #### Relying Party ID
468
+
469
+ A passkey is bound to the domain that created it. By default, a passkey created on `example.com` cannot be used on `app.example.com`. Set `rpID` to the registrable parent domain to share passkeys between a domain and its subdomains:
470
+
471
+ ```ts
472
+ export default defineNuxtConfig({
473
+ auth: {
474
+ webAuthn: {
475
+ rpID: 'example.com', // passkeys created on `example.com` also work on `app.example.com`
476
+ rpName: 'My App' // shown by the authenticator when creating a passkey
477
+ }
478
+ }
479
+ })
480
+ ```
481
+
482
+ Both options default to the hostname of the request. The module uses `rpID` to generate the options and to verify the response, and `rpName` only to label the passkey during registration. Both are read from `runtimeConfig`, which helps when one build serves several domains:
483
+
484
+ ```ts
485
+ export default defineNuxtConfig({
486
+ runtimeConfig: {
487
+ webauthn: {
488
+ rpID: 'example.com'
489
+ }
490
+ }
491
+ })
492
+ ```
493
+
494
+ `NUXT_WEBAUTHN_RP_ID` and `NUXT_WEBAUTHN_RP_NAME` override both at runtime.
495
+
496
+ When you define `getOptions`, the module calls it while generating the options and again while verifying the response. Return the same `rpID` in both calls, or verification fails with an `Unexpected RP ID hash` error. The expected origin is always the origin of the request, because that is what the browser sends back.
497
+
435
498
  #### Example
436
499
 
437
500
  In this example we will implement the very basic steps to register and authenticate a credential.
@@ -965,13 +1028,13 @@ Releases are automated with [uppt](https://github.com/danielroe/uppt): every pus
965
1028
 
966
1029
  <!-- Badges -->
967
1030
  [npm-version-src]: https://img.shields.io/npm/v/nuxt-auth-utils/latest.svg?style=flat&colorA=020420&colorB=00DC82
968
- [npm-version-href]: https://npmjs.com/package/nuxt-auth-utils
1031
+ [npm-version-href]: https://npmx.dev/package/nuxt-auth-utils
969
1032
 
970
1033
  [npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-auth-utils.svg?style=flat&colorA=020420&colorB=00DC82
971
- [npm-downloads-href]: https://npm.chart.dev/nuxt-auth-utils
1034
+ [npm-downloads-href]: https://npmx.dev/package-stats/nuxt-auth-utils/v/latest?granularity=monthly
972
1035
 
973
1036
  [license-src]: https://img.shields.io/npm/l/nuxt-auth-utils.svg?style=flat&colorA=020420&colorB=00DC82
974
- [license-href]: https://npmjs.com/package/nuxt-auth-utils
1037
+ [license-href]: https://github.com/atinux/nuxt-auth-utils/blob/main/LICENSE
975
1038
 
976
1039
  [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
977
1040
  [nuxt-href]: https://nuxt.com
package/dist/module.d.mts CHANGED
@@ -1,12 +1,28 @@
1
1
  import { ScryptConfig } from '@adonisjs/hash/types';
2
+ import { GenerateRegistrationOptionsOpts, GenerateAuthenticationOptionsOpts } from '@simplewebauthn/server';
2
3
  import { SessionConfig } from 'nuxt/server';
4
+ import { OAuthRuntimeConfig } from '../dist/runtime/types/oauth-runtime-config.js';
3
5
 
6
+ interface WebAuthnOptions {
7
+ /**
8
+ * Relying Party ID the passkeys are bound to.
9
+ *
10
+ * Set the registrable parent domain (such as `example.com`) to create and use passkeys across subdomains.
11
+ * @default the request hostname
12
+ */
13
+ rpID?: string;
14
+ /**
15
+ * Relying Party name shown by the authenticator when creating a passkey
16
+ * @default the request hostname
17
+ */
18
+ rpName?: string;
19
+ }
4
20
  interface ModuleOptions {
5
21
  /**
6
22
  * Enable WebAuthn (Passkeys)
7
23
  * @default false
8
24
  */
9
- webAuthn?: boolean;
25
+ webAuthn?: boolean | WebAuthnOptions;
10
26
  /**
11
27
  * Enable atproto OAuth (Bluesky, etc.)
12
28
  * @default false
@@ -36,6 +52,24 @@ declare module 'nuxt/schema' {
36
52
  * Session configuration, the session is sealed with a secret derived from `appSecret` (`NUXT_APP_SECRET`)
37
53
  */
38
54
  session: Omit<SessionConfig, 'password'>;
55
+ /**
56
+ * WebAuthn settings, `rpID` and `rpName` are set from the `webAuthn` module option.
57
+ *
58
+ * Both can be overridden at runtime with `NUXT_WEBAUTHN_RP_ID` and `NUXT_WEBAUTHN_RP_NAME`.
59
+ *
60
+ * `register` and `authenticate` are merged into the options passed to
61
+ * `generateRegistrationOptions()` and `generateAuthenticationOptions()`.
62
+ */
63
+ webauthn: {
64
+ rpID: string;
65
+ rpName: string;
66
+ register: Partial<GenerateRegistrationOptionsOpts>;
67
+ authenticate: Partial<GenerateAuthenticationOptionsOpts>;
68
+ };
69
+ /**
70
+ * OAuth providers configuration, one key per provider (`github`, `google`, `keycloak`, ...).
71
+ */
72
+ oauth: OAuthRuntimeConfig;
39
73
  }
40
74
  interface PublicRuntimeConfig {
41
75
  auth: {
@@ -46,4 +80,4 @@ declare module 'nuxt/schema' {
46
80
  declare const _default: any;
47
81
 
48
82
  export { _default as default };
49
- export type { ModuleOptions };
83
+ export type { ModuleOptions, WebAuthnOptions };
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=4.6.0"
6
6
  },
7
- "version": "0.6.1",
7
+ "version": "0.6.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.3",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -91,7 +91,10 @@ const module$1 = defineNuxtModule({
91
91
  runtimeConfig.public.auth = defu(runtimeConfig.public.auth, {
92
92
  loadStrategy: options.loadStrategy ?? "server-first"
93
93
  });
94
+ const webAuthnOptions = typeof options.webAuthn === "object" ? options.webAuthn : void 0;
94
95
  runtimeConfig.webauthn = defu(runtimeConfig.webauthn, {
96
+ rpID: webAuthnOptions?.rpID ?? "",
97
+ rpName: webAuthnOptions?.rpName ?? "",
95
98
  register: {},
96
99
  authenticate: {}
97
100
  });
@@ -145,7 +148,7 @@ const module$1 = defineNuxtModule({
145
148
  clientId: "",
146
149
  clientSecret: "",
147
150
  connectionId: "",
148
- screenHint: "",
151
+ screenHint: "sign-in",
149
152
  redirectURL: ""
150
153
  });
151
154
  runtimeConfig.oauth.microsoft = defu(runtimeConfig.oauth.microsoft, {
@@ -360,25 +363,25 @@ const module$1 = defineNuxtModule({
360
363
  redirectURL: "",
361
364
  baseURL: "",
362
365
  userURL: "",
363
- scope: ""
366
+ scope: []
364
367
  });
365
368
  runtimeConfig.oauth.slack = defu(runtimeConfig.oauth.slack, {
366
369
  clientId: "",
367
370
  clientSecret: "",
368
371
  redirectURL: "",
369
- scope: ""
372
+ scope: []
370
373
  });
371
374
  runtimeConfig.oauth.heroku = defu(runtimeConfig.oauth.heroku, {
372
375
  clientId: "",
373
376
  clientSecret: "",
374
377
  redirectURL: "",
375
- scope: ""
378
+ scope: []
376
379
  });
377
380
  runtimeConfig.oauth.roblox = defu(runtimeConfig.oauth.roblox, {
378
381
  clientId: "",
379
382
  clientSecret: "",
380
383
  redirectURL: "",
381
- scope: ""
384
+ scope: []
382
385
  });
383
386
  runtimeConfig.oauth.okta = defu(runtimeConfig.oauth.okta, {
384
387
  clientId: "",
@@ -1,10 +1,12 @@
1
- import { defineEventHandler, createError, deleteCookie, getCookie, getQuery, sendRedirect, setCookie } from "nuxt/server";
1
+ import { defineEventHandler, createError, deleteCookie, getCookie, getQuery, getRequestURL, sendRedirect, setCookie, useRuntimeConfig } from "nuxt/server";
2
2
  import { NodeOAuthClient, OAuthCallbackError, OAuthResolverError, OAuthResponseError } from "@atproto/oauth-client-node";
3
3
  import { Agent } from "@atproto/api";
4
+ import { withoutBase } from "ufo";
4
5
  import { getAtprotoClientMetadata } from "../../utils/atproto.js";
5
6
  export function defineOAuthBlueskyEventHandler({ config, onSuccess, onError }) {
6
7
  return defineEventHandler(async (event) => {
7
8
  const clientMetadata = getAtprotoClientMetadata(event, "bluesky", config);
9
+ if (import.meta.dev && !config?.redirectUrl) warnUnpublishedLoginPath(event, clientMetadata.redirect_uris[0]);
8
10
  const scopes = clientMetadata.scope?.split(" ") ?? [];
9
11
  const sessionStore = new SessionStore();
10
12
  const stateStore = new StateStore(event);
@@ -65,6 +67,17 @@ export function defineOAuthBlueskyEventHandler({ config, onSuccess, onError }) {
65
67
  }
66
68
  });
67
69
  }
70
+ let warnedUnpublishedLoginPath = false;
71
+ function warnUnpublishedLoginPath(event, redirectUri) {
72
+ if (warnedUnpublishedLoginPath) return;
73
+ const runtimeConfig = useRuntimeConfig();
74
+ if (runtimeConfig.oauth.bluesky.redirectUris?.length) return;
75
+ const loginPath = getRequestURL(event).pathname;
76
+ const callbackPath = new URL(redirectUri).pathname;
77
+ if (loginPath === callbackPath) return;
78
+ warnedUnpublishedLoginPath = true;
79
+ console.warn(`[nuxt-auth-utils] The Bluesky login route is served from \`${loginPath}\`, but Bluesky redirects back to \`${callbackPath}\`. Set \`runtimeConfig.oauth.bluesky.redirectUris\` to \`['${withoutBase(loginPath, runtimeConfig.app.baseURL)}']\`.`);
80
+ }
68
81
  export class StateStore {
69
82
  constructor(event) {
70
83
  this.event = event;
@@ -32,7 +32,7 @@ export function defineOAuthHerokuEventHandler({
32
32
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
33
33
  const state = await handleState(event);
34
34
  if (!query.code) {
35
- config.scope = config.scope || ["identity"];
35
+ config.scope = config.scope?.length ? config.scope : ["identity"];
36
36
  return sendRedirect(
37
37
  event,
38
38
  withQuery(config.authorizationURL, {
@@ -1,5 +1,4 @@
1
- import { defineEventHandler, getQuery, sendRedirect, useRuntimeConfig } from "nuxt/server";
2
- import { $fetch } from "ofetch";
1
+ import { createError, defineEventHandler, getQuery, sendRedirect, useRuntimeConfig } from "nuxt/server";
3
2
  import { withQuery } from "ufo";
4
3
  import defu from "defu";
5
4
  import {
@@ -37,7 +36,7 @@ export function defineOAuthHubspotEventHandler({ config, onSuccess, onError }) {
37
36
  return handleInvalidState(event, "hubspot", onError);
38
37
  }
39
38
  const tokens = await requestAccessToken(
40
- "https://api.hubapi.com/oauth/v1/token",
39
+ "https://api.hubapi.com/oauth/2026-09/token",
41
40
  {
42
41
  body: {
43
42
  client_id: config.clientId,
@@ -51,7 +50,29 @@ export function defineOAuthHubspotEventHandler({ config, onSuccess, onError }) {
51
50
  if (tokens.error) {
52
51
  return handleAccessTokenErrorResponse(event, "hubspot", tokens, onError);
53
52
  }
54
- const info = await $fetch("https://api.hubapi.com/oauth/v1/access-tokens/" + tokens.access_token);
53
+ const info = await requestAccessToken(
54
+ "https://api.hubapi.com/oauth/2026-09/token/introspect",
55
+ {
56
+ params: {
57
+ client_id: config.clientId,
58
+ client_secret: config.clientSecret,
59
+ token: tokens.access_token,
60
+ token_type_hint: "access_token"
61
+ }
62
+ }
63
+ );
64
+ if (info.error) {
65
+ return handleAccessTokenErrorResponse(event, "hubspot", info, onError);
66
+ }
67
+ if (!info.active) {
68
+ const error = createError({
69
+ status: 401,
70
+ message: "Hubspot login failed: the access token is not active",
71
+ data: info
72
+ });
73
+ if (!onError) throw error;
74
+ return onError(event, error);
75
+ }
55
76
  return onSuccess(event, {
56
77
  user: {
57
78
  id: info.user_id,
@@ -33,7 +33,7 @@ export function defineOAuthSalesforceEventHandler({
33
33
  const pkce = await handlePkceVerifier(event);
34
34
  const state = await handleState(event);
35
35
  if (!query.code) {
36
- config.scope = config.scope || ["id"];
36
+ config.scope = config.scope?.length ? config.scope : ["id"];
37
37
  return sendRedirect(
38
38
  event,
39
39
  withQuery(config.authorizationURL, {
@@ -32,7 +32,7 @@ export function defineOAuthSlackEventHandler({
32
32
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
33
33
  const state = await handleState(event);
34
34
  if (!query.code) {
35
- config.scope = config.scope || ["openid", "email", "profile"];
35
+ config.scope = config.scope?.length ? config.scope : ["openid", "email", "profile"];
36
36
  return sendRedirect(
37
37
  event,
38
38
  withQuery(config.authorizationURL, {
@@ -15,8 +15,9 @@ export function defineWebAuthnAuthenticateEventHandler({
15
15
  return defineEventHandler(async (event) => {
16
16
  const url = getRequestURL(event, { xForwardedProto: true });
17
17
  const body = await readBody(event);
18
- const _config = defu(await getOptions?.(event, body) ?? {}, useRuntimeConfig().webauthn.authenticate, {
19
- rpID: url.hostname
18
+ const runtimeConfig = useRuntimeConfig();
19
+ const _config = defu(await getOptions?.(event, body) ?? {}, runtimeConfig.webauthn.authenticate, {
20
+ rpID: runtimeConfig.webauthn.rpID || url.hostname
20
21
  });
21
22
  if (!storeChallenge) {
22
23
  _config.challenge = "";
@@ -47,7 +48,7 @@ export function defineWebAuthnAuthenticateEventHandler({
47
48
  response: body.response,
48
49
  expectedChallenge,
49
50
  expectedOrigin: url.origin,
50
- expectedRPID: url.hostname,
51
+ expectedRPID: _config.rpID,
51
52
  requireUserVerification: false,
52
53
  // TODO: make configurable https://simplewebauthn.dev/docs/advanced/passkeys#verifyauthenticationresponse
53
54
  credential: {
@@ -24,9 +24,10 @@ export function defineWebAuthnRegisterEventHandler({
24
24
  if (validateUser) {
25
25
  user = await validateUserData(body.user, event, validateUser);
26
26
  }
27
- const _config = defu(await getOptions?.(event, body) ?? {}, useRuntimeConfig().webauthn.register, {
28
- rpID: url.hostname,
29
- rpName: url.hostname,
27
+ const runtimeConfig = useRuntimeConfig();
28
+ const _config = defu(await getOptions?.(event, body) ?? {}, runtimeConfig.webauthn.register, {
29
+ rpID: runtimeConfig.webauthn.rpID || url.hostname,
30
+ rpName: runtimeConfig.webauthn.rpName || url.hostname,
30
31
  userName: user.userName,
31
32
  userDisplayName: user.displayName,
32
33
  authenticatorSelection: {
@@ -65,7 +66,7 @@ export function defineWebAuthnRegisterEventHandler({
65
66
  response: body.response,
66
67
  expectedChallenge,
67
68
  expectedOrigin: url.origin,
68
- expectedRPID: url.hostname,
69
+ expectedRPID: _config.rpID,
69
70
  requireUserVerification: false,
70
71
  // TODO: make configurable https://simplewebauthn.dev/docs/advanced/passkeys#verifyregistrationresponse
71
72
  supportedAlgorithmIDs: _config.supportedAlgorithmIDs
@@ -1,22 +1,23 @@
1
1
  import { getRequestURL, useRuntimeConfig } from "nuxt/server";
2
- import { getOAuthRedirectURL } from "../lib/utils.js";
2
+ import { withBase } from "ufo";
3
3
  import { getClientMetadataFilename } from "../../utils/atproto.js";
4
4
  export function getAtprotoClientMetadata(event, provider, config) {
5
- const providerRuntimeConfig = useRuntimeConfig().oauth[provider];
5
+ const runtimeConfig = useRuntimeConfig();
6
+ const providerRuntimeConfig = runtimeConfig.oauth[provider];
6
7
  const scopes = [.../* @__PURE__ */ new Set(["atproto", ...config?.scope ?? [], ...providerRuntimeConfig.scope ?? []])];
7
8
  const scope = scopes.join(" ");
8
9
  const grantTypes = [.../* @__PURE__ */ new Set(["authorization_code", ...providerRuntimeConfig.grantTypes ?? []])];
9
10
  const requestURL = getRequestURL(event, { xForwardedProto: true });
10
11
  const baseUrl = `${requestURL.protocol}//${requestURL.host}`;
11
- const redirectURL = new URL(
12
- config?.redirectUrl && baseUrl + config.redirectUrl || providerRuntimeConfig.redirectUris[0] && baseUrl + providerRuntimeConfig.redirectUris[0] || getOAuthRedirectURL(event)
13
- );
12
+ const withAppBase = (path) => withBase(path, runtimeConfig.app.baseURL);
13
+ const callbackPaths = (providerRuntimeConfig.redirectUris?.length ? providerRuntimeConfig.redirectUris : [`/auth/${provider}`]).map(withAppBase);
14
+ const redirectURL = new URL(baseUrl + (config?.redirectUrl ? withAppBase(config.redirectUrl) : callbackPaths[0]));
14
15
  const dev = import.meta.dev;
15
16
  if (dev && redirectURL.hostname === "localhost") {
16
17
  redirectURL.hostname = "127.0.0.1";
17
18
  }
18
- const redirectUris = (providerRuntimeConfig.redirectUris.length ? providerRuntimeConfig.redirectUris : [requestURL.pathname]).map((uri) => new URL(`${redirectURL.protocol}//${redirectURL.host}${uri}`).toString());
19
- const clientId = dev ? `http://localhost?redirect_uri=${encodeURIComponent(redirectURL.toString())}&scope=${encodeURIComponent(scope)}` : `${baseUrl}/${getClientMetadataFilename("bluesky", providerRuntimeConfig)}`;
19
+ const redirectUris = callbackPaths.map((uri) => new URL(`${redirectURL.protocol}//${redirectURL.host}${uri}`).toString());
20
+ const clientId = dev ? `http://localhost?redirect_uri=${encodeURIComponent(redirectURL.toString())}&scope=${encodeURIComponent(scope)}` : `${baseUrl}${withBase(`/${getClientMetadataFilename(provider, providerRuntimeConfig)}`, runtimeConfig.app.baseURL)}`;
20
21
  const clientMetadata = {
21
22
  client_name: providerRuntimeConfig.clientName || void 0,
22
23
  client_uri: providerRuntimeConfig.clientUri || void 0,
@@ -1,5 +1,5 @@
1
1
  import type { OAuthClientMetadata } from '@atproto/oauth-client-node';
2
- export interface AtprotoProviderClientMetadata {
2
+ export type AtprotoProviderClientMetadata = {
3
3
  /**
4
4
  * The name of the client metadata file. This is used to construct the client ID.
5
5
  * @example 'client-metadata.json'
@@ -46,10 +46,12 @@ export interface AtprotoProviderClientMetadata {
46
46
  */
47
47
  responseTypes?: OAuthClientMetadata['response_types'];
48
48
  /**
49
- * At least one redirect URI is required. The URL origin must match that of the `clientId`, so declare only the path.
49
+ * At least one redirect URI is required. The URL origin must match that of the `clientId`, so declare only the path. Paths are resolved under the app base URL.
50
+ *
51
+ * Empty by default, in which case `/auth/<provider>` under the app base URL is used.
50
52
  * @example ['/auth/callback']
51
53
  */
52
- redirectUris: OAuthClientMetadata['redirect_uris'];
54
+ redirectUris?: `/${string}`[];
53
55
  /**
54
56
  * The token endpoint authentication method. `none` is the default, and the only supported value at this time.
55
57
  * @default 'none'
@@ -59,4 +61,4 @@ export interface AtprotoProviderClientMetadata {
59
61
  * DPoP is mandatory for all clients, so this must be present and true.
60
62
  */
61
63
  dpopBoundAccessTokens?: OAuthClientMetadata['dpop_bound_access_tokens'];
62
- }
64
+ };
@@ -1,4 +1,4 @@
1
1
  export type { User, UserSession, UserSessionRequired, UserSessionComposable, SecureSessionData } from './session.js';
2
2
  export type { RequestEvent, SessionEvent, LegacyH3Event, WebSocketSessionEvent } from './event.js';
3
- export type { OAuthConfig, OAuthProvider, ATProtoProvider, OnError } from './oauth-config.js';
3
+ export type { OAuthConfig, OAuthProvider, ATProtoProvider, OAuthRuntimeConfigExtension, OnError } from './oauth-config.js';
4
4
  export type { WebAuthnCredential, WebAuthnRegisterEventHandlerOptions, WebAuthnAuthenticateEventHandlerOptions, WebAuthnComposable, WebAuthnUser, } from './webauthn.js';
@@ -2,6 +2,20 @@ import type { NuxtError, RequestEvent } from 'nuxt/server';
2
2
  export type ATProtoProvider = 'bluesky';
3
3
  export type OAuthProvider = ATProtoProvider | 'atlassian' | 'auth0' | 'authentik' | 'azureb2c' | 'battledotnet' | 'cloudflare' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'gitea' | 'github' | 'gitlab' | 'google' | 'hubspot' | 'instagram' | 'kick' | 'keycloak' | 'line' | 'linear' | 'linkedin' | 'mastodon' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'wechat' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | 'apple' | 'livechat' | 'salesforce' | 'slack' | 'heroku' | 'roblox' | 'okta' | 'ory' | 'shopifyCustomer' | 'oidc' | 'osu' | 'riotgames' | 'box' | 'zendesk' | (string & {});
4
4
  export type OnError = (event: RequestEvent, error: NuxtError) => unknown;
5
+ /**
6
+ * Augment this interface to type the runtime configuration of OAuth providers that are not
7
+ * shipped with the module, such as providers added by another module.
8
+ *
9
+ * ```ts
10
+ * declare module '#auth-utils' {
11
+ * interface OAuthRuntimeConfigExtension {
12
+ * myProvider: { clientId: string, clientSecret: string }
13
+ * }
14
+ * }
15
+ * ```
16
+ */
17
+ export interface OAuthRuntimeConfigExtension {
18
+ }
5
19
  export interface OAuthConfig<TConfig, TResult = {
6
20
  user: any;
7
21
  tokens: any;
@@ -0,0 +1,119 @@
1
+ import type { AtprotoProviderClientMetadata } from './atproto.js';
2
+ import type { OAuthRuntimeConfigExtension } from './oauth-config.js';
3
+ import type { LiveChatConfig } from '../server/lib/oauth/livechat.js';
4
+ import type { OAuthAppleConfig } from '../server/lib/oauth/apple.js';
5
+ import type { OAuthAtlassianConfig } from '../server/lib/oauth/atlassian.js';
6
+ import type { OAuthAuth0Config } from '../server/lib/oauth/auth0.js';
7
+ import type { OAuthAuthentikConfig } from '../server/lib/oauth/authentik.js';
8
+ import type { OAuthAzureB2CConfig } from '../server/lib/oauth/azureb2c.js';
9
+ import type { OAuthBattledotnetConfig } from '../server/lib/oauth/battledotnet.js';
10
+ import type { OAuthBoxConfig } from '../server/lib/oauth/box.js';
11
+ import type { OAuthCloudflareConfig } from '../server/lib/oauth/cloudflare.js';
12
+ import type { OAuthCognitoConfig } from '../server/lib/oauth/cognito.js';
13
+ import type { OAuthDiscordConfig } from '../server/lib/oauth/discord.js';
14
+ import type { OAuthDropboxConfig } from '../server/lib/oauth/dropbox.js';
15
+ import type { OAuthFacebookConfig } from '../server/lib/oauth/facebook.js';
16
+ import type { OAuthGitHubConfig } from '../server/lib/oauth/github.js';
17
+ import type { OAuthGitLabConfig } from '../server/lib/oauth/gitlab.js';
18
+ import type { OAuthGiteaConfig } from '../server/lib/oauth/gitea.js';
19
+ import type { OAuthGoogleConfig } from '../server/lib/oauth/google.js';
20
+ import type { OAuthHerokuConfig } from '../server/lib/oauth/heroku.js';
21
+ import type { OAuthHubspotConfig } from '../server/lib/oauth/hubspot.js';
22
+ import type { OAuthInstagramConfig } from '../server/lib/oauth/instagram.js';
23
+ import type { OAuthKeycloakConfig } from '../server/lib/oauth/keycloak.js';
24
+ import type { OAuthKickConfig } from '../server/lib/oauth/kick.js';
25
+ import type { OAuthLineConfig } from '../server/lib/oauth/line.js';
26
+ import type { OAuthLinearConfig } from '../server/lib/oauth/linear.js';
27
+ import type { OAuthLinkedInConfig } from '../server/lib/oauth/linkedin.js';
28
+ import type { OAuthMastodonConfig } from '../server/lib/oauth/mastodon.js';
29
+ import type { OAuthMicrosoftConfig } from '../server/lib/oauth/microsoft.js';
30
+ import type { OAuthOidcConfig } from '../server/lib/oauth/oidc.js';
31
+ import type { OAuthOktaConfig } from '../server/lib/oauth/okta.js';
32
+ import type { OAuthOryConfig } from '../server/lib/oauth/ory.js';
33
+ import type { OAuthOsuConfig } from '../server/lib/oauth/osu.js';
34
+ import type { OAuthPaypalConfig } from '../server/lib/oauth/paypal.js';
35
+ import type { OAuthPolarConfig } from '../server/lib/oauth/polar.js';
36
+ import type { OAuthRiotGamesConfig } from '../server/lib/oauth/riotgames.js';
37
+ import type { OAuthRobloxConfig } from '../server/lib/oauth/roblox.js';
38
+ import type { OAuthSalesforceConfig } from '../server/lib/oauth/salesforce.js';
39
+ import type { OAuthSeznamConfig } from '../server/lib/oauth/seznam.js';
40
+ import type { OAuthShopifyCustomerConfig } from '../server/lib/oauth/shopifyCustomer.js';
41
+ import type { OAuthSlackConfig } from '../server/lib/oauth/slack.js';
42
+ import type { OAuthSpotifyConfig } from '../server/lib/oauth/spotify.js';
43
+ import type { OAuthSteamConfig } from '../server/lib/oauth/steam.js';
44
+ import type { OAuthStravaConfig } from '../server/lib/oauth/strava.js';
45
+ import type { OAuthTikTokConfig } from '../server/lib/oauth/tiktok.js';
46
+ import type { OAuthTwitchConfig } from '../server/lib/oauth/twitch.js';
47
+ import type { OAuthVKConfig } from '../server/lib/oauth/vk.js';
48
+ import type { OAuthWechatConfig } from '../server/lib/oauth/wechat.js';
49
+ import type { OAuthWorkOSConfig } from '../server/lib/oauth/workos.js';
50
+ import type { OAuthXConfig } from '../server/lib/oauth/x.js';
51
+ import type { OAuthXSUAAConfig } from '../server/lib/oauth/xsuaa.js';
52
+ import type { OAuthYandexConfig } from '../server/lib/oauth/yandex.js';
53
+ import type { OAuthZendeskConfig } from '../server/lib/oauth/zendesk.js';
54
+ import type { OAuthZitadelConfig } from '../server/lib/oauth/zitadel.js';
55
+ /**
56
+ * Runtime configuration of every OAuth provider supported by the module, exposed as `runtimeConfig.oauth`.
57
+ *
58
+ * Keys are the provider names accepted by `defineOAuth<Provider>EventHandler()`, and they are always
59
+ * set by the module, so server code can read them without checking for `undefined`. In `nuxt.config`,
60
+ * `runtimeConfig` is deep-partial, so you only write the providers you use.
61
+ * Providers contributed by other modules can add themselves through the `OAuthRuntimeConfigExtension`
62
+ * interface, and any other key stays `unknown`.
63
+ */
64
+ export interface OAuthRuntimeConfig extends OAuthRuntimeConfigExtension {
65
+ [provider: string]: unknown;
66
+ apple: OAuthAppleConfig;
67
+ atlassian: OAuthAtlassianConfig;
68
+ auth0: OAuthAuth0Config;
69
+ authentik: OAuthAuthentikConfig;
70
+ azureb2c: OAuthAzureB2CConfig;
71
+ battledotnet: OAuthBattledotnetConfig;
72
+ bluesky: AtprotoProviderClientMetadata;
73
+ box: OAuthBoxConfig;
74
+ cloudflare: OAuthCloudflareConfig;
75
+ cognito: OAuthCognitoConfig;
76
+ discord: OAuthDiscordConfig;
77
+ dropbox: OAuthDropboxConfig;
78
+ facebook: OAuthFacebookConfig;
79
+ gitea: OAuthGiteaConfig;
80
+ github: OAuthGitHubConfig;
81
+ gitlab: OAuthGitLabConfig;
82
+ google: OAuthGoogleConfig;
83
+ heroku: OAuthHerokuConfig;
84
+ hubspot: OAuthHubspotConfig;
85
+ instagram: OAuthInstagramConfig;
86
+ keycloak: OAuthKeycloakConfig;
87
+ kick: OAuthKickConfig;
88
+ line: OAuthLineConfig;
89
+ linear: OAuthLinearConfig;
90
+ linkedin: OAuthLinkedInConfig;
91
+ livechat: LiveChatConfig;
92
+ mastodon: OAuthMastodonConfig;
93
+ microsoft: OAuthMicrosoftConfig;
94
+ oidc: OAuthOidcConfig;
95
+ okta: OAuthOktaConfig;
96
+ ory: OAuthOryConfig;
97
+ osu: OAuthOsuConfig;
98
+ paypal: OAuthPaypalConfig;
99
+ polar: OAuthPolarConfig;
100
+ riotgames: OAuthRiotGamesConfig;
101
+ roblox: OAuthRobloxConfig;
102
+ salesforce: OAuthSalesforceConfig;
103
+ seznam: OAuthSeznamConfig;
104
+ shopifyCustomer: OAuthShopifyCustomerConfig;
105
+ slack: OAuthSlackConfig;
106
+ spotify: OAuthSpotifyConfig;
107
+ steam: OAuthSteamConfig;
108
+ strava: OAuthStravaConfig;
109
+ tiktok: OAuthTikTokConfig;
110
+ twitch: OAuthTwitchConfig;
111
+ vk: OAuthVKConfig;
112
+ wechat: OAuthWechatConfig;
113
+ workos: OAuthWorkOSConfig;
114
+ x: OAuthXConfig;
115
+ xsuaa: OAuthXSUAAConfig;
116
+ yandex: OAuthYandexConfig;
117
+ zendesk: OAuthZendeskConfig;
118
+ zitadel: OAuthZitadelConfig;
119
+ }
File without changes
@@ -10,8 +10,7 @@ export const atprotoProviderDefaultClientMetadata = {
10
10
  grantTypes: ["authorization_code"],
11
11
  responseTypes: ["code"],
12
12
  applicationType: "web",
13
- // @ts-expect-error TypeScript is too smart for its own good
14
- redirectUris: void 0,
13
+ redirectUris: [],
15
14
  dpopBoundAccessTokens: true,
16
15
  tokenEndpointAuthMethod: "none"
17
16
  };
package/dist/types.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default } from './module.mjs'
2
2
 
3
- export { type ModuleOptions } from './module.mjs'
3
+ export { type ModuleOptions, type WebAuthnOptions } from './module.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-auth-utils",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Add Authentication to Nuxt applications with secured & sealed cookies sessions.",
5
5
  "repository": {
6
6
  "type": "git",