nuxt-auth-utils 0.3.3 → 0.3.5

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.
Files changed (45) hide show
  1. package/README.md +2 -0
  2. package/dist/module.d.mts +1 -1
  3. package/dist/module.d.ts +1 -1
  4. package/dist/module.json +2 -2
  5. package/dist/module.mjs +33 -17
  6. package/dist/runtime/app/plugins/session.client.js +3 -1
  7. package/dist/runtime/server/lib/oauth/auth0.d.ts +5 -0
  8. package/dist/runtime/server/lib/oauth/auth0.js +7 -17
  9. package/dist/runtime/server/lib/oauth/battledotnet.d.ts +5 -0
  10. package/dist/runtime/server/lib/oauth/battledotnet.js +11 -17
  11. package/dist/runtime/server/lib/oauth/cognito.d.ts +10 -0
  12. package/dist/runtime/server/lib/oauth/cognito.js +11 -20
  13. package/dist/runtime/server/lib/oauth/discord.d.ts +5 -0
  14. package/dist/runtime/server/lib/oauth/discord.js +7 -17
  15. package/dist/runtime/server/lib/oauth/facebook.d.ts +5 -0
  16. package/dist/runtime/server/lib/oauth/facebook.js +6 -16
  17. package/dist/runtime/server/lib/oauth/github.d.ts +6 -0
  18. package/dist/runtime/server/lib/oauth/github.js +5 -15
  19. package/dist/runtime/server/lib/oauth/google.d.ts +5 -0
  20. package/dist/runtime/server/lib/oauth/google.js +6 -17
  21. package/dist/runtime/server/lib/oauth/keycloak.d.ts +5 -0
  22. package/dist/runtime/server/lib/oauth/keycloak.js +6 -16
  23. package/dist/runtime/server/lib/oauth/linkedin.d.ts +5 -0
  24. package/dist/runtime/server/lib/oauth/linkedin.js +7 -17
  25. package/dist/runtime/server/lib/oauth/microsoft.d.ts +1 -1
  26. package/dist/runtime/server/lib/oauth/microsoft.js +6 -16
  27. package/dist/runtime/server/lib/oauth/paypal.d.ts +5 -0
  28. package/dist/runtime/server/lib/oauth/paypal.js +6 -16
  29. package/dist/runtime/server/lib/oauth/spotify.d.ts +5 -0
  30. package/dist/runtime/server/lib/oauth/spotify.js +7 -17
  31. package/dist/runtime/server/lib/oauth/steam.d.ts +5 -0
  32. package/dist/runtime/server/lib/oauth/steam.js +4 -8
  33. package/dist/runtime/server/lib/oauth/twitch.d.ts +5 -0
  34. package/dist/runtime/server/lib/oauth/twitch.js +6 -16
  35. package/dist/runtime/server/lib/oauth/x.d.ts +6 -6
  36. package/dist/runtime/server/lib/oauth/x.js +10 -44
  37. package/dist/runtime/server/lib/oauth/xsuaa.d.ts +5 -0
  38. package/dist/runtime/server/lib/oauth/xsuaa.js +7 -17
  39. package/dist/runtime/server/lib/oauth/yandex.d.ts +5 -0
  40. package/dist/runtime/server/lib/oauth/yandex.js +6 -17
  41. package/dist/runtime/server/lib/utils.d.ts +9 -0
  42. package/dist/runtime/server/lib/utils.js +21 -0
  43. package/dist/runtime/types/index.d.ts +1 -1
  44. package/dist/runtime/types/oauth-config.d.ts +3 -1
  45. package/package.json +11 -10
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  eventHandler,
3
- createError,
4
3
  getQuery,
5
4
  getRequestURL,
6
5
  sendRedirect
7
6
  } from "h3";
8
7
  import { withQuery, parsePath } from "ufo";
9
8
  import { defu } from "defu";
9
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
10
10
  import { useRuntimeConfig } from "#imports";
11
11
  export function oauthGoogleEventHandler({
12
12
  config,
@@ -22,14 +22,9 @@ export function oauthGoogleEventHandler({
22
22
  });
23
23
  const { code } = getQuery(event);
24
24
  if (!config.clientId) {
25
- const error = createError({
26
- statusCode: 500,
27
- message: "Missing NUXT_OAUTH_GOOGLE_CLIENT_ID env variables."
28
- });
29
- if (!onError) throw error;
30
- return onError(event, error);
25
+ return handleMissingConfiguration(event, "google", ["clientId"], onError);
31
26
  }
32
- const redirectUrl = getRequestURL(event).href;
27
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
33
28
  if (!code) {
34
29
  config.scope = config.scope || ["email", "profile"];
35
30
  return sendRedirect(
@@ -37,7 +32,7 @@ export function oauthGoogleEventHandler({
37
32
  withQuery(config.authorizationURL, {
38
33
  response_type: "code",
39
34
  client_id: config.clientId,
40
- redirect_uri: redirectUrl,
35
+ redirect_uri: redirectURL,
41
36
  scope: config.scope.join(" "),
42
37
  ...config.authorizationParams
43
38
  })
@@ -45,7 +40,7 @@ export function oauthGoogleEventHandler({
45
40
  }
46
41
  const body = {
47
42
  grant_type: "authorization_code",
48
- redirect_uri: parsePath(redirectUrl).pathname,
43
+ redirect_uri: parsePath(redirectURL).pathname,
49
44
  client_id: config.clientId,
50
45
  client_secret: config.clientSecret,
51
46
  code
@@ -57,13 +52,7 @@ export function oauthGoogleEventHandler({
57
52
  return { error };
58
53
  });
59
54
  if (tokens.error) {
60
- const error = createError({
61
- statusCode: 401,
62
- message: `Google login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
63
- data: tokens
64
- });
65
- if (!onError) throw error;
66
- return onError(event, error);
55
+ return handleAccessTokenErrorResponse(event, "google", tokens, onError);
67
56
  }
68
57
  const accessToken = tokens.access_token;
69
58
  const user = await $fetch(
@@ -32,5 +32,10 @@ export interface OAuthKeycloakConfig {
32
32
  * Extra authorization parameters to provide to the authorization URL
33
33
  */
34
34
  authorizationParams?: Record<string, string>;
35
+ /**
36
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
37
+ * @default process.env.NUXT_OAUTH_KEYCLOAK_REDIRECT_URL or current URL
38
+ */
39
+ redirectURL?: string;
35
40
  }
36
41
  export declare function oauthKeycloakEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthKeycloakConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -7,6 +7,7 @@ import {
7
7
  } from "h3";
8
8
  import { withQuery, parsePath } from "ufo";
9
9
  import { defu } from "defu";
10
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
10
11
  import { useRuntimeConfig } from "#imports";
11
12
  export function oauthKeycloakEventHandler({
12
13
  config,
@@ -29,24 +30,19 @@ export function oauthKeycloakEventHandler({
29
30
  return onError(event, error);
30
31
  }
31
32
  if (!config.clientId || !config.clientSecret || !config.serverUrl || !config.realm) {
32
- const error = createError({
33
- statusCode: 500,
34
- message: "Missing NUXT_OAUTH_KEYCLOAK_CLIENT_ID or NUXT_OAUTH_KEYCLOAK_CLIENT_SECRET or NUXT_OAUTH_KEYCLOAK_SERVER_URL or NUXT_OAUTH_KEYCLOAK_REALM env variables."
35
- });
36
- if (!onError) throw error;
37
- return onError(event, error);
33
+ return handleMissingConfiguration(event, "keycloak", ["clientId", "clientSecret", "serverUrl", "realm"], onError);
38
34
  }
39
35
  const realmURL = `${config.serverUrl}/realms/${config.realm}`;
40
36
  const authorizationURL = `${realmURL}/protocol/openid-connect/auth`;
41
37
  const tokenURL = `${realmURL}/protocol/openid-connect/token`;
42
- const redirectUrl = getRequestURL(event).href;
38
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
43
39
  if (!code) {
44
40
  config.scope = config.scope || ["openid"];
45
41
  return sendRedirect(
46
42
  event,
47
43
  withQuery(authorizationURL, {
48
44
  client_id: config.clientId,
49
- redirect_uri: redirectUrl,
45
+ redirect_uri: redirectURL,
50
46
  scope: config.scope.join(" "),
51
47
  response_type: "code",
52
48
  ...config.authorizationParams
@@ -66,20 +62,14 @@ export function oauthKeycloakEventHandler({
66
62
  client_id: config.clientId,
67
63
  client_secret: config.clientSecret,
68
64
  grant_type: "authorization_code",
69
- redirect_uri: parsePath(redirectUrl).pathname,
65
+ redirect_uri: parsePath(redirectURL).pathname,
70
66
  code
71
67
  }).toString()
72
68
  }).catch((error) => {
73
69
  return { error };
74
70
  });
75
71
  if (tokens.error) {
76
- const error = createError({
77
- statusCode: 401,
78
- message: `Keycloak login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
79
- data: tokens
80
- });
81
- if (!onError) throw error;
82
- return onError(event, error);
72
+ return handleAccessTokenErrorResponse(event, "keycloak", tokens, onError);
83
73
  }
84
74
  const accessToken = tokens.access_token;
85
75
  const user = await $fetch(
@@ -36,6 +36,11 @@ export interface OAuthLinkedInConfig {
36
36
  * @see https://docs.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?context=linkedin/context
37
37
  */
38
38
  authorizationParams?: Record<string, string>;
39
+ /**
40
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
41
+ * @default process.env.NUXT_OAUTH_LINKEDIN_REDIRECT_URL or current URL
42
+ */
43
+ redirectURL?: string;
39
44
  }
40
45
  interface OAuthConfig {
41
46
  config?: OAuthLinkedInConfig;
@@ -1,6 +1,7 @@
1
- import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
1
+ import { eventHandler, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parseURL, stringifyParsedURL } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthLinkedInEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -11,14 +12,9 @@ export function oauthLinkedInEventHandler({ config, onSuccess, onError }) {
11
12
  });
12
13
  const { code } = getQuery(event);
13
14
  if (!config.clientId || !config.clientSecret) {
14
- const error = createError({
15
- statusCode: 500,
16
- message: "Missing NUXT_OAUTH_LINKEDIN_CLIENT_ID or NUXT_OAUTH_LINKEDIN_CLIENT_SECRET env variables."
17
- });
18
- if (!onError) throw error;
19
- return onError(event, error);
15
+ return handleMissingConfiguration(event, "linkedin", ["clientId", "clientSecret"], onError);
20
16
  }
21
- const redirectUrl = getRequestURL(event).href;
17
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
22
18
  if (!code) {
23
19
  config.scope = config.scope || [];
24
20
  if (!config.scope.length) {
@@ -32,13 +28,13 @@ export function oauthLinkedInEventHandler({ config, onSuccess, onError }) {
32
28
  withQuery(config.authorizationURL, {
33
29
  response_type: "code",
34
30
  client_id: config.clientId,
35
- redirect_uri: redirectUrl,
31
+ redirect_uri: redirectURL,
36
32
  scope: config.scope.join(" "),
37
33
  ...config.authorizationParams
38
34
  })
39
35
  );
40
36
  }
41
- const parsedRedirectUrl = parseURL(redirectUrl);
37
+ const parsedRedirectUrl = parseURL(redirectURL);
42
38
  parsedRedirectUrl.search = "";
43
39
  const tokens = await $fetch(
44
40
  config.tokenURL,
@@ -59,13 +55,7 @@ export function oauthLinkedInEventHandler({ config, onSuccess, onError }) {
59
55
  return { error };
60
56
  });
61
57
  if (tokens.error) {
62
- const error = createError({
63
- statusCode: 401,
64
- message: `LinkedIn login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
65
- data: tokens
66
- });
67
- if (!onError) throw error;
68
- return onError(event, error);
58
+ return handleAccessTokenErrorResponse(event, "linkedin", tokens, onError);
69
59
  }
70
60
  const accessToken = tokens.access_token;
71
61
  const user = await $fetch("https://api.linkedin.com/v2/userinfo", {
@@ -49,7 +49,7 @@ export interface OAuthMicrosoftConfig {
49
49
  * @default process.env.NUXT_OAUTH_MICROSOFT_REDIRECT_URL
50
50
  * @see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
51
51
  */
52
- redirectUrl?: string;
52
+ redirectURL?: string;
53
53
  }
54
54
  interface OAuthConfig {
55
55
  config?: OAuthMicrosoftConfig;
@@ -1,6 +1,7 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -9,16 +10,11 @@ export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
9
10
  });
10
11
  const { code } = getQuery(event);
11
12
  if (!config.clientId || !config.clientSecret || !config.tenant) {
12
- const error = createError({
13
- statusCode: 500,
14
- message: "Missing NUXT_OAUTH_MICROSOFT_CLIENT_ID or NUXT_OAUTH_MICROSOFT_CLIENT_SECRET or NUXT_OAUTH_MICROSOFT_TENANT env variables."
15
- });
16
- if (!onError) throw error;
17
- return onError(event, error);
13
+ return handleMissingConfiguration(event, "microsoft", ["clientId", "clientSecret", "tenant"], onError);
18
14
  }
19
15
  const authorizationURL = config.authorizationURL || `https://login.microsoftonline.com/${config.tenant}/oauth2/v2.0/authorize`;
20
16
  const tokenURL = config.tokenURL || `https://login.microsoftonline.com/${config.tenant}/oauth2/v2.0/token`;
21
- const redirectUrl = config.redirectUrl || getRequestURL(event).href;
17
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
22
18
  if (!code) {
23
19
  const scope = config.scope && config.scope.length > 0 ? config.scope : ["User.Read"];
24
20
  return sendRedirect(
@@ -26,7 +22,7 @@ export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
26
22
  withQuery(authorizationURL, {
27
23
  client_id: config.clientId,
28
24
  response_type: "code",
29
- redirect_uri: redirectUrl,
25
+ redirect_uri: redirectURL,
30
26
  scope: scope.join(" "),
31
27
  ...config.authorizationParams
32
28
  })
@@ -36,7 +32,7 @@ export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
36
32
  data.append("grant_type", "authorization_code");
37
33
  data.append("client_id", config.clientId);
38
34
  data.append("client_secret", config.clientSecret);
39
- data.append("redirect_uri", parsePath(redirectUrl).pathname);
35
+ data.append("redirect_uri", parsePath(redirectURL).pathname);
40
36
  data.append("code", String(code));
41
37
  const tokens = await $fetch(
42
38
  tokenURL,
@@ -51,13 +47,7 @@ export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
51
47
  return { error };
52
48
  });
53
49
  if (tokens.error) {
54
- const error = createError({
55
- statusCode: 401,
56
- message: `Microsoft login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
57
- data: tokens
58
- });
59
- if (!onError) throw error;
60
- return onError(event, error);
50
+ return handleAccessTokenErrorResponse(event, "microsoft", tokens, onError);
61
51
  }
62
52
  const tokenType = tokens.token_type;
63
53
  const accessToken = tokens.access_token;
@@ -43,5 +43,10 @@ export interface OAuthPaypalConfig {
43
43
  * @example { flowEntry: 'static' }
44
44
  */
45
45
  authorizationParams?: Record<string, string>;
46
+ /**
47
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
48
+ * @default process.env.NUXT_OAUTH_PAYPAL_REDIRECT_URL or current URL
49
+ */
50
+ redirectURL?: string;
46
51
  }
47
52
  export declare function oauthPaypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -1,6 +1,7 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -12,12 +13,7 @@ export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
12
13
  });
13
14
  const { code } = getQuery(event);
14
15
  if (!config.clientId) {
15
- const error = createError({
16
- statusCode: 500,
17
- message: "Missing NUXT_OAUTH_PAYPAL_CLIENT_ID env variables."
18
- });
19
- if (!onError) throw error;
20
- return onError(event, error);
16
+ return handleMissingConfiguration(event, "paypal", ["clientId"], onError);
21
17
  }
22
18
  let paypalAPI = "api-m.paypal.com";
23
19
  if (config.sandbox) {
@@ -25,7 +21,7 @@ export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
25
21
  config.authorizationURL = "https://www.sandbox.paypal.com/signin/authorize";
26
22
  config.tokenURL = `https://${paypalAPI}/v1/oauth2/token`;
27
23
  }
28
- const redirectUrl = getRequestURL(event).href;
24
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
29
25
  if (!code) {
30
26
  config.scope = config.scope || [];
31
27
  if (!config.scope.includes("openid")) {
@@ -39,7 +35,7 @@ export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
39
35
  withQuery(config.authorizationURL, {
40
36
  response_type: "code",
41
37
  client_id: config.clientId,
42
- redirect_uri: redirectUrl,
38
+ redirect_uri: redirectURL,
43
39
  scope: config.scope.join(" "),
44
40
  flowEntry: "static",
45
41
  ...config.authorizationParams
@@ -57,7 +53,7 @@ export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
57
53
  },
58
54
  params: {
59
55
  grant_type: "authorization_code",
60
- redirect_uri: encodeURIComponent(parsePath(redirectUrl).pathname),
56
+ redirect_uri: encodeURIComponent(parsePath(redirectURL).pathname),
61
57
  code
62
58
  }
63
59
  }
@@ -65,13 +61,7 @@ export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
65
61
  return { error };
66
62
  });
67
63
  if (tokens.error) {
68
- const error = createError({
69
- statusCode: 401,
70
- message: `PayPal login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
71
- data: tokens
72
- });
73
- if (!onError) throw error;
74
- return onError(event, error);
64
+ return handleAccessTokenErrorResponse(event, "paypal", tokens, onError);
75
65
  }
76
66
  const accessToken = tokens.access_token;
77
67
  const users = await $fetch(`https://${paypalAPI}/v1/identity/openidconnect/userinfo`, {
@@ -38,5 +38,10 @@ export interface OAuthSpotifyConfig {
38
38
  * @example { show_dialog: 'true' }
39
39
  */
40
40
  authorizationParams?: Record<string, string>;
41
+ /**
42
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
43
+ * @default process.env.NUXT_OAUTH_SPOTIFY_REDIRECT_URL or current URL
44
+ */
45
+ redirectURL?: string;
41
46
  }
42
47
  export declare function oauthSpotifyEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSpotifyConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -1,6 +1,7 @@
1
- import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
1
+ import { eventHandler, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -11,14 +12,9 @@ export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
11
12
  });
12
13
  const { code } = getQuery(event);
13
14
  if (!config.clientId || !config.clientSecret) {
14
- const error = createError({
15
- statusCode: 500,
16
- message: "Missing NUXT_OAUTH_SPOTIFY_CLIENT_ID or NUXT_OAUTH_SPOTIFY_CLIENT_SECRET env variables."
17
- });
18
- if (!onError) throw error;
19
- return onError(event, error);
15
+ return handleMissingConfiguration(event, "spotify", ["clientId", "clientSecret"], onError);
20
16
  }
21
- const redirectUrl = getRequestURL(event).href;
17
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
22
18
  if (!code) {
23
19
  config.scope = config.scope || [];
24
20
  if (config.emailRequired && !config.scope.includes("user-read-email")) {
@@ -29,7 +25,7 @@ export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
29
25
  withQuery(config.authorizationURL, {
30
26
  response_type: "code",
31
27
  client_id: config.clientId,
32
- redirect_uri: redirectUrl,
28
+ redirect_uri: redirectURL,
33
29
  scope: config.scope.join(" "),
34
30
  ...config.authorizationParams
35
31
  })
@@ -46,7 +42,7 @@ export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
46
42
  },
47
43
  params: {
48
44
  grant_type: "authorization_code",
49
- redirect_uri: parsePath(redirectUrl).pathname,
45
+ redirect_uri: parsePath(redirectURL).pathname,
50
46
  code
51
47
  }
52
48
  }
@@ -54,13 +50,7 @@ export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
54
50
  return { error };
55
51
  });
56
52
  if (tokens.error) {
57
- const error = createError({
58
- statusCode: 401,
59
- message: `Spotify login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
60
- data: tokens
61
- });
62
- if (!onError) throw error;
63
- return onError(event, error);
53
+ return handleAccessTokenErrorResponse(event, "spotify", tokens, onError);
64
54
  }
65
55
  const accessToken = tokens.access_token;
66
56
  const user = await $fetch("https://api.spotify.com/v1/me", {
@@ -11,5 +11,10 @@ export interface OAuthSteamConfig {
11
11
  * @default 'https://steamcommunity.com/openid/login'
12
12
  */
13
13
  authorizationURL?: string;
14
+ /**
15
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
16
+ * @default process.env.NUXT_OAUTH_STEAM_REDIRECT_URL or current URL
17
+ */
18
+ redirectURL?: string;
14
19
  }
15
20
  export declare function oauthSteamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSteamConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -1,6 +1,7 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthSteamEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -9,19 +10,14 @@ export function oauthSteamEventHandler({ config, onSuccess, onError }) {
9
10
  });
10
11
  const query = getQuery(event);
11
12
  if (!config.apiKey) {
12
- const error = createError({
13
- statusCode: 500,
14
- message: "Missing NUXT_OAUTH_STEAM_API_KEY env variable."
15
- });
16
- if (!onError) throw error;
17
- return onError(event, error);
13
+ return handleMissingConfiguration(event, "steam", ["apiKey"], onError);
18
14
  }
19
15
  if (!query["openid.claimed_id"]) {
20
- const redirectUrl = getRequestURL(event).href;
16
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
21
17
  const steamOpenIdParams = {
22
18
  "openid.ns": "http://specs.openid.net/auth/2.0",
23
19
  "openid.mode": "checkid_setup",
24
- "openid.return_to": redirectUrl,
20
+ "openid.return_to": redirectURL,
25
21
  "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select",
26
22
  "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select"
27
23
  };
@@ -38,5 +38,10 @@ export interface OAuthTwitchConfig {
38
38
  * @example { force_verify: 'true' }
39
39
  */
40
40
  authorizationParams?: Record<string, string>;
41
+ /**
42
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
43
+ * @default process.env.NUXT_OAUTH_TWITCH_REDIRECT_URL or current URL
44
+ */
45
+ redirectURL?: string;
41
46
  }
42
47
  export declare function oauthTwitchEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTwitchConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -1,6 +1,7 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
3
  import { defu } from "defu";
4
+ import { handleAccessTokenErrorResponse, handleMissingConfiguration } from "../utils.js";
4
5
  import { useRuntimeConfig } from "#imports";
5
6
  export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
6
7
  return eventHandler(async (event) => {
@@ -11,14 +12,9 @@ export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
11
12
  });
12
13
  const { code } = getQuery(event);
13
14
  if (!config.clientId) {
14
- const error = createError({
15
- statusCode: 500,
16
- message: "Missing NUXT_OAUTH_TWITCH_CLIENT_ID env variables."
17
- });
18
- if (!onError) throw error;
19
- return onError(event, error);
15
+ return handleMissingConfiguration(event, "twitch", ["clientId"], onError);
20
16
  }
21
- const redirectUrl = getRequestURL(event).href;
17
+ const redirectURL = config.redirectURL || getRequestURL(event).href;
22
18
  if (!code) {
23
19
  config.scope = config.scope || [];
24
20
  if (config.emailRequired && !config.scope.includes("user:read:email")) {
@@ -29,7 +25,7 @@ export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
29
25
  withQuery(config.authorizationURL, {
30
26
  response_type: "code",
31
27
  client_id: config.clientId,
32
- redirect_uri: redirectUrl,
28
+ redirect_uri: redirectURL,
33
29
  scope: config.scope.join(" "),
34
30
  ...config.authorizationParams
35
31
  })
@@ -44,7 +40,7 @@ export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
44
40
  },
45
41
  params: {
46
42
  grant_type: "authorization_code",
47
- redirect_uri: parsePath(redirectUrl).pathname,
43
+ redirect_uri: parsePath(redirectURL).pathname,
48
44
  client_id: config.clientId,
49
45
  client_secret: config.clientSecret,
50
46
  code
@@ -54,13 +50,7 @@ export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
54
50
  return { error };
55
51
  });
56
52
  if (tokens.error) {
57
- const error = createError({
58
- statusCode: 401,
59
- message: `Twitch login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
60
- data: tokens
61
- });
62
- if (!onError) throw error;
63
- return onError(event, error);
53
+ return handleAccessTokenErrorResponse(event, "twitch", tokens, onError);
64
54
  }
65
55
  const accessToken = tokens.access_token;
66
56
  const users = await $fetch("https://api.twitch.tv/helix/users", {
@@ -17,11 +17,6 @@ export interface OAuthXConfig {
17
17
  * @example ['tweet.read', 'users.read', 'offline.access'],
18
18
  */
19
19
  scope?: string[];
20
- /**
21
- * Require email from user
22
- * @default false
23
- */
24
- emailRequired?: boolean;
25
20
  /**
26
21
  * X OAuth Authorization URL
27
22
  * @default 'https://twitter.com/i/oauth2/authorize'
@@ -41,6 +36,11 @@ export interface OAuthXConfig {
41
36
  * Extra authorization parameters to provide to the authorization URL
42
37
  * @see https://developer.x.com/en/docs/authentication/oauth-2-0/user-access-token
43
38
  */
44
- authorizationParams: Record<string, string>;
39
+ authorizationParams?: Record<string, string>;
40
+ /**
41
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
42
+ * @default process.env.NUXT_OAUTH_X_REDIRECT_URL or current URL
43
+ */
44
+ redirectURL?: string;
45
45
  }
46
46
  export declare function oauthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;