nuxt-auth-utils 0.5.29 → 0.5.30

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 (53) hide show
  1. package/README.md +1 -1
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/app/plugins/session.client.js +1 -1
  4. package/dist/runtime/server/lib/oauth/apple.js +12 -3
  5. package/dist/runtime/server/lib/oauth/atlassian.js +7 -4
  6. package/dist/runtime/server/lib/oauth/auth0.js +7 -2
  7. package/dist/runtime/server/lib/oauth/authentik.js +7 -2
  8. package/dist/runtime/server/lib/oauth/azureb2c.js +2 -2
  9. package/dist/runtime/server/lib/oauth/battledotnet.js +7 -5
  10. package/dist/runtime/server/lib/oauth/box.js +2 -2
  11. package/dist/runtime/server/lib/oauth/cognito.js +7 -2
  12. package/dist/runtime/server/lib/oauth/discord.js +7 -2
  13. package/dist/runtime/server/lib/oauth/dropbox.js +7 -2
  14. package/dist/runtime/server/lib/oauth/facebook.js +7 -3
  15. package/dist/runtime/server/lib/oauth/gitea.js +8 -1
  16. package/dist/runtime/server/lib/oauth/github.js +2 -2
  17. package/dist/runtime/server/lib/oauth/gitlab.js +8 -1
  18. package/dist/runtime/server/lib/oauth/google.js +7 -3
  19. package/dist/runtime/server/lib/oauth/heroku.js +2 -2
  20. package/dist/runtime/server/lib/oauth/hubspot.js +8 -1
  21. package/dist/runtime/server/lib/oauth/instagram.js +7 -2
  22. package/dist/runtime/server/lib/oauth/keycloak.js +7 -2
  23. package/dist/runtime/server/lib/oauth/kick.js +6 -3
  24. package/dist/runtime/server/lib/oauth/line.js +7 -3
  25. package/dist/runtime/server/lib/oauth/linear.js +7 -2
  26. package/dist/runtime/server/lib/oauth/linkedin.js +7 -2
  27. package/dist/runtime/server/lib/oauth/livechat.js +9 -5
  28. package/dist/runtime/server/lib/oauth/microsoft.js +7 -3
  29. package/dist/runtime/server/lib/oauth/oidc.js +2 -2
  30. package/dist/runtime/server/lib/oauth/okta.js +3 -4
  31. package/dist/runtime/server/lib/oauth/ory.js +2 -2
  32. package/dist/runtime/server/lib/oauth/osu.js +2 -2
  33. package/dist/runtime/server/lib/oauth/paypal.js +7 -2
  34. package/dist/runtime/server/lib/oauth/polar.js +7 -2
  35. package/dist/runtime/server/lib/oauth/riotgames.js +2 -2
  36. package/dist/runtime/server/lib/oauth/roblox.js +7 -2
  37. package/dist/runtime/server/lib/oauth/salesforce.js +2 -2
  38. package/dist/runtime/server/lib/oauth/seznam.js +6 -2
  39. package/dist/runtime/server/lib/oauth/shopifyCustomer.js +4 -1
  40. package/dist/runtime/server/lib/oauth/slack.js +2 -2
  41. package/dist/runtime/server/lib/oauth/spotify.js +7 -2
  42. package/dist/runtime/server/lib/oauth/steam.js +6 -2
  43. package/dist/runtime/server/lib/oauth/strava.js +8 -1
  44. package/dist/runtime/server/lib/oauth/tiktok.js +7 -2
  45. package/dist/runtime/server/lib/oauth/twitch.js +7 -2
  46. package/dist/runtime/server/lib/oauth/vk.js +7 -1
  47. package/dist/runtime/server/lib/oauth/workos.js +7 -2
  48. package/dist/runtime/server/lib/oauth/xsuaa.js +7 -2
  49. package/dist/runtime/server/lib/oauth/yandex.js +8 -1
  50. package/dist/runtime/server/lib/oauth/zitadel.js +2 -2
  51. package/dist/runtime/server/lib/utils.d.ts +5 -1
  52. package/dist/runtime/server/lib/utils.js +11 -9
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -418,7 +418,7 @@ export default defineWebAuthnRegisterEventHandler({
418
418
  // And verify that the email is the same as the one in session
419
419
  const session = await getUserSession(event)
420
420
  if (session.user?.email && session.user.email !== userBody.userName) {
421
- throw createError({ statusCode: 400, message: 'Email not matching curent session' })
421
+ throw createError({ statusCode: 400, message: 'Email not matching current session' })
422
422
  }
423
423
 
424
424
  // If he registers a new account with credentials
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.5.29",
4
+ "version": "0.5.30",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -3,7 +3,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
3
3
  if (!nuxtApp.payload.serverRendered) {
4
4
  await useUserSession().fetch();
5
5
  } else if (Boolean(nuxtApp.payload.prerenderedAt) || Boolean(nuxtApp.payload.isCached) || nuxtApp.$config.public.auth.loadStrategy === "client-only") {
6
- nuxtApp.hook("app:mounted", async () => {
6
+ nuxtApp.hook("app:suspense:resolve", async () => {
7
7
  await useUserSession().fetch();
8
8
  });
9
9
  }
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getRequestHeader, readBody, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken, signJwt, verifyJwt } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken, signJwt, verifyJwt } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthAppleEventHandler({
7
7
  config,
@@ -19,10 +19,15 @@ export function defineOAuthAppleEventHandler({
19
19
  }
20
20
  const isPost = getRequestHeader(event, "content-type") === "application/x-www-form-urlencoded";
21
21
  let code;
22
+ let state;
22
23
  let user;
23
24
  if (isPost) {
24
- ({ code, user } = await readBody(event));
25
+ ({ code, state, user } = await readBody(event));
25
26
  }
27
+ const storedState = await handleState(event, {
28
+ isCallback: isPost && Boolean(code),
29
+ sameSite: "none"
30
+ });
26
31
  if (!isPost || !code) {
27
32
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
28
33
  config.scope = Array.isArray(config.scope) ? config.scope.join(" ") : config.scope || "name email";
@@ -34,10 +39,14 @@ export function defineOAuthAppleEventHandler({
34
39
  client_id: config.clientId,
35
40
  redirect_uri: redirectURL,
36
41
  scope: config.scope,
37
- ...config.authorizationParams
42
+ ...config.authorizationParams,
43
+ state: storedState
38
44
  })
39
45
  );
40
46
  }
47
+ if (state !== storedState) {
48
+ return handleInvalidState(event, "apple", onError);
49
+ }
41
50
  try {
42
51
  const secret = await signJwt(
43
52
  {
@@ -1,8 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { randomUUID } from "uncrypto";
5
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
6
5
  import { useRuntimeConfig, createError } from "#imports";
7
6
  export function defineOAuthAtlassianEventHandler({
8
7
  config,
@@ -28,6 +27,7 @@ export function defineOAuthAtlassianEventHandler({
28
27
  }
29
28
  const query = getQuery(event);
30
29
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
30
+ const state = await handleState(event);
31
31
  if (!query.code) {
32
32
  return sendRedirect(
33
33
  event,
@@ -36,10 +36,10 @@ export function defineOAuthAtlassianEventHandler({
36
36
  client_id: config.clientId,
37
37
  scope: config.scope?.join(" "),
38
38
  redirect_uri: redirectURL,
39
- state: randomUUID(),
40
39
  response_type: "code",
41
40
  prompt: "consent",
42
- ...config.authorizationParams
41
+ ...config.authorizationParams,
42
+ state
43
43
  })
44
44
  );
45
45
  }
@@ -52,6 +52,9 @@ export function defineOAuthAtlassianEventHandler({
52
52
  if (!onError) throw error;
53
53
  return onError(event, error);
54
54
  }
55
+ if (query.state !== state) {
56
+ return handleInvalidState(event, "atlassian", onError);
57
+ }
55
58
  const tokens = await requestAccessToken(config.tokenURL, {
56
59
  headers: {
57
60
  "Content-Type": "application/json"
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
@@ -26,6 +26,7 @@ export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
26
26
  onError
27
27
  );
28
28
  }
29
+ const state = await handleState(event);
29
30
  if (!query.code) {
30
31
  config.scope = config.scope || ["openid", "offline_access"];
31
32
  if (config.emailRequired && !config.scope.includes("email")) {
@@ -41,10 +42,14 @@ export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
41
42
  audience: config.audience || "",
42
43
  max_age: config.maxAge || 0,
43
44
  connection: config.connection || "",
44
- ...config.authorizationParams
45
+ ...config.authorizationParams,
46
+ state
45
47
  })
46
48
  );
47
49
  }
50
+ if (query.state !== state) {
51
+ return handleInvalidState(event, "auth0", onError);
52
+ }
48
53
  const tokens = await requestAccessToken(tokenURL, {
49
54
  headers: {
50
55
  "Content-Type": "application/json"
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
6
  export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
@@ -22,6 +22,7 @@ export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError })
22
22
  const authorizationURL = `https://${config.domain}/application/o/authorize/`;
23
23
  const tokenURL = `https://${config.domain}/application/o/token/`;
24
24
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
25
+ const state = await handleState(event);
25
26
  if (!query.code) {
26
27
  return sendRedirect(
27
28
  event,
@@ -29,10 +30,14 @@ export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError })
29
30
  response_type: "code",
30
31
  client_id: config.clientId,
31
32
  redirect_uri: redirectURL,
32
- scope: (config.scope || ["openid", "profile", "email"]).join(" ")
33
+ scope: (config.scope || ["openid", "profile", "email"]).join(" "),
34
+ state
33
35
  })
34
36
  );
35
37
  }
38
+ if (query.state !== state) {
39
+ return handleInvalidState(event, "authentik", onError);
40
+ }
36
41
  const tokens = await requestAccessToken(tokenURL, {
37
42
  headers: {
38
43
  "Authorization": `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`,
@@ -27,10 +27,10 @@ export function defineOAuthAzureB2CEventHandler({ config, onSuccess, onError })
27
27
  response_type: "code",
28
28
  redirect_uri: redirectURL,
29
29
  scope: config.scope.join(" "),
30
- state,
31
30
  code_challenge: verifier.code_challenge,
32
31
  code_challenge_method: verifier.code_challenge_method,
33
- ...config.authorizationParams
32
+ ...config.authorizationParams,
33
+ state
34
34
  })
35
35
  );
36
36
  }
@@ -1,8 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { randomUUID } from "uncrypto";
5
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
6
5
  import { useRuntimeConfig, createError } from "#imports";
7
6
  export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError }) {
8
7
  return eventHandler(async (event) => {
@@ -30,6 +29,7 @@ export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError
30
29
  );
31
30
  }
32
31
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
32
+ const state = await handleState(event);
33
33
  if (!query.code) {
34
34
  config.scope = config.scope || ["openid"];
35
35
  config.region = config.region || "EU";
@@ -43,13 +43,15 @@ export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError
43
43
  client_id: config.clientId,
44
44
  redirect_uri: redirectURL,
45
45
  scope: config.scope.join(" "),
46
- state: randomUUID(),
47
- // Todo: handle PKCE flow
48
46
  response_type: "code",
49
- ...config.authorizationParams
47
+ ...config.authorizationParams,
48
+ state
50
49
  })
51
50
  );
52
51
  }
52
+ if (query.state !== state) {
53
+ return handleInvalidState(event, "battledotnet", onError);
54
+ }
53
55
  config.scope = config.scope || [];
54
56
  if (!config.scope.includes("openid")) {
55
57
  config.scope.push("openid");
@@ -36,8 +36,8 @@ export function defineOAuthBoxEventHandler({ config, onSuccess, onError }) {
36
36
  client_id: config.clientId,
37
37
  redirect_uri: redirectURL,
38
38
  scope: scope.join(" "),
39
- state,
40
- ...config.authorizationParams
39
+ ...config.authorizationParams,
40
+ state
41
41
  })
42
42
  );
43
43
  }
@@ -2,7 +2,7 @@ import { defu } from "defu";
2
2
  import { eventHandler, getQuery, sendRedirect } from "h3";
3
3
  import { discovery } from "openid-client";
4
4
  import { withQuery } from "ufo";
5
- import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleMissingConfiguration, requestAccessToken } from "../utils.js";
5
+ import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleInvalidState, handleMissingConfiguration, handleState, requestAccessToken } from "../utils.js";
6
6
  import { useRuntimeConfig } from "#imports";
7
7
  export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
8
8
  return eventHandler(async (event) => {
@@ -24,6 +24,7 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
24
24
  } = issuer.serverMetadata();
25
25
  const query = getQuery(event);
26
26
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
27
+ const state = await handleState(event);
27
28
  if (!query.code) {
28
29
  config.scope = config.scope || ["openid", "profile"];
29
30
  return sendRedirect(
@@ -33,10 +34,14 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
33
34
  redirect_uri: redirectURL,
34
35
  response_type: "code",
35
36
  scope: config.scope.join(" "),
36
- ...config.authorizationParams
37
+ ...config.authorizationParams,
38
+ state
37
39
  })
38
40
  );
39
41
  }
42
+ if (query.state !== state) {
43
+ return handleInvalidState(event, "cognito", onError);
44
+ }
40
45
  const tokens = await requestAccessToken(
41
46
  tokenURL,
42
47
  {
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
@@ -19,6 +19,7 @@ export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
19
19
  return handleAccessTokenErrorResponse(event, "discord", query, onError);
20
20
  }
21
21
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
22
+ const state = await handleState(event);
22
23
  if (!query.code) {
23
24
  config.scope = config.scope || [];
24
25
  if (config.emailRequired && !config.scope.includes("email")) {
@@ -34,10 +35,14 @@ export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
34
35
  client_id: config.clientId,
35
36
  redirect_uri: redirectURL,
36
37
  scope: config.scope.join(" "),
37
- ...config.authorizationParams
38
+ ...config.authorizationParams,
39
+ state
38
40
  })
39
41
  );
40
42
  }
43
+ if (query.state !== state) {
44
+ return handleInvalidState(event, "discord", onError);
45
+ }
41
46
  const tokens = await requestAccessToken(config.tokenURL, {
42
47
  body: {
43
48
  client_id: config.clientId,
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
6
  export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
@@ -15,6 +15,7 @@ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
15
15
  return handleMissingConfiguration(event, "dropbox", ["clientId", "clientSecret"], onError);
16
16
  }
17
17
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
18
+ const state = await handleState(event);
18
19
  if (!query.code) {
19
20
  config.scope = config.scope || [];
20
21
  if (!config.scope.includes("openid")) {
@@ -30,10 +31,14 @@ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
30
31
  client_id: config.clientId,
31
32
  redirect_uri: redirectURL,
32
33
  scope: config.scope.join(" "),
33
- ...config.authorizationParams
34
+ ...config.authorizationParams,
35
+ state
34
36
  })
35
37
  );
36
38
  }
39
+ if (query.state !== state) {
40
+ return handleInvalidState(event, "dropbox", onError);
41
+ }
37
42
  const tokens = await requestAccessToken(config.tokenURL, {
38
43
  headers: {
39
44
  Authorization: `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect, createError } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthFacebookEventHandler({
7
7
  config,
@@ -28,6 +28,7 @@ export function defineOAuthFacebookEventHandler({
28
28
  return handleMissingConfiguration(event, "facebook", ["clientId", "clientSecret"], onError);
29
29
  }
30
30
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
31
+ const state = await handleState(event);
31
32
  if (!query.code) {
32
33
  config.scope = [...new Set(config.scope)];
33
34
  return sendRedirect(
@@ -36,11 +37,14 @@ export function defineOAuthFacebookEventHandler({
36
37
  client_id: config.clientId,
37
38
  redirect_uri: redirectURL,
38
39
  scope: config.scope.join(" "),
39
- state: query.state || "",
40
- ...config.authorizationParams
40
+ ...config.authorizationParams,
41
+ state
41
42
  })
42
43
  );
43
44
  }
45
+ if (query.state !== state) {
46
+ return handleInvalidState(event, "facebook", onError);
47
+ }
44
48
  const tokens = await requestAccessToken(config.tokenURL, {
45
49
  body: {
46
50
  client_id: config.clientId,
@@ -5,6 +5,8 @@ import {
5
5
  handleMissingConfiguration,
6
6
  handleAccessTokenErrorResponse,
7
7
  getOAuthRedirectURL,
8
+ handleInvalidState,
9
+ handleState,
8
10
  requestAccessToken
9
11
  } from "../utils.js";
10
12
  import { useRuntimeConfig, createError } from "#imports";
@@ -40,6 +42,7 @@ export function defineOAuthGiteaEventHandler({
40
42
  );
41
43
  }
42
44
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
45
+ const state = await handleState(event);
43
46
  if (!query.code) {
44
47
  config.scope = config.scope || [];
45
48
  if (!config.scope.length) {
@@ -55,10 +58,14 @@ export function defineOAuthGiteaEventHandler({
55
58
  client_id: config.clientId,
56
59
  redirect_uri: redirectURL,
57
60
  scope: config.scope.join(" "),
58
- ...config.authorizationParams
61
+ ...config.authorizationParams,
62
+ state
59
63
  })
60
64
  );
61
65
  }
66
+ if (query.state !== state) {
67
+ return handleInvalidState(event, "gitea", onError);
68
+ }
62
69
  const tokens = await requestAccessToken(config.tokenURL, {
63
70
  body: {
64
71
  grant_type: "authorization_code",
@@ -37,8 +37,8 @@ export function defineOAuthGitHubEventHandler({ config, onSuccess, onError }) {
37
37
  client_id: config.clientId,
38
38
  redirect_uri: redirectURL,
39
39
  scope: config.scope.join(" "),
40
- state,
41
- ...config.authorizationParams
40
+ ...config.authorizationParams,
41
+ state
42
42
  })
43
43
  );
44
44
  }
@@ -5,6 +5,8 @@ import {
5
5
  handleMissingConfiguration,
6
6
  handleAccessTokenErrorResponse,
7
7
  getOAuthRedirectURL,
8
+ handleInvalidState,
9
+ handleState,
8
10
  requestAccessToken
9
11
  } from "../utils.js";
10
12
  import { useRuntimeConfig, createError } from "#imports";
@@ -40,6 +42,7 @@ export function defineOAuthGitLabEventHandler({
40
42
  );
41
43
  }
42
44
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
45
+ const state = await handleState(event);
43
46
  if (!query.code) {
44
47
  config.scope = config.scope || [];
45
48
  if (!config.scope.length) {
@@ -55,10 +58,14 @@ export function defineOAuthGitLabEventHandler({
55
58
  client_id: config.clientId,
56
59
  redirect_uri: redirectURL,
57
60
  scope: config.scope.join(" "),
58
- ...config.authorizationParams
61
+ ...config.authorizationParams,
62
+ state
59
63
  })
60
64
  );
61
65
  }
66
+ if (query.state !== state) {
67
+ return handleInvalidState(event, "gitlab", onError);
68
+ }
62
69
  const tokens = await requestAccessToken(config.tokenURL, {
63
70
  body: {
64
71
  grant_type: "authorization_code",
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthGoogleEventHandler({
7
7
  config,
@@ -20,6 +20,7 @@ export function defineOAuthGoogleEventHandler({
20
20
  return handleMissingConfiguration(event, "google", ["clientId", "clientSecret"], onError);
21
21
  }
22
22
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
23
+ const state = await handleState(event);
23
24
  if (!query.code) {
24
25
  config.scope = config.scope || ["email", "profile"];
25
26
  return sendRedirect(
@@ -29,11 +30,14 @@ export function defineOAuthGoogleEventHandler({
29
30
  client_id: config.clientId,
30
31
  redirect_uri: redirectURL,
31
32
  scope: config.scope.join(" "),
32
- state: query.state || "",
33
- ...config.authorizationParams
33
+ ...config.authorizationParams,
34
+ state
34
35
  })
35
36
  );
36
37
  }
38
+ if (query.state !== state) {
39
+ return handleInvalidState(event, "google", onError);
40
+ }
37
41
  const tokens = await requestAccessToken(config.tokenURL, {
38
42
  body: {
39
43
  grant_type: "authorization_code",
@@ -40,8 +40,8 @@ export function defineOAuthHerokuEventHandler({
40
40
  client_id: config.clientId,
41
41
  redirect_uri: redirectURL,
42
42
  scope: config.scope.join(" "),
43
- state,
44
- ...config.authorizationParams
43
+ ...config.authorizationParams,
44
+ state
45
45
  })
46
46
  );
47
47
  }
@@ -5,6 +5,8 @@ import {
5
5
  getOAuthRedirectURL,
6
6
  handleAccessTokenErrorResponse,
7
7
  handleMissingConfiguration,
8
+ handleInvalidState,
9
+ handleState,
8
10
  requestAccessToken
9
11
  } from "../utils.js";
10
12
  import { useRuntimeConfig } from "#imports";
@@ -19,16 +21,21 @@ export function defineOAuthHubspotEventHandler({ config, onSuccess, onError }) {
19
21
  if (query.error) {
20
22
  return handleAccessTokenErrorResponse(event, "hubspot", query, onError);
21
23
  }
24
+ const state = await handleState(event);
22
25
  if (!query.code) {
23
26
  return sendRedirect(
24
27
  event,
25
28
  withQuery("https://app.hubspot.com/oauth/authorize", {
26
29
  client_id: config.clientId,
27
30
  redirect_uri: redirectURL,
28
- scope: config.scope?.join(" ") || "oauth"
31
+ scope: config.scope?.join(" ") || "oauth",
32
+ state
29
33
  })
30
34
  );
31
35
  }
36
+ if (query.state !== state) {
37
+ return handleInvalidState(event, "hubspot", onError);
38
+ }
32
39
  const tokens = await requestAccessToken(
33
40
  "https://api.hubapi.com/oauth/v1/token",
34
41
  {
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect, createError } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
6
  export function defineOAuthInstagramEventHandler({
7
7
  config,
@@ -33,6 +33,7 @@ export function defineOAuthInstagramEventHandler({
33
33
  return handleMissingConfiguration(event, "instagram", ["clientId", "clientSecret"], onError);
34
34
  }
35
35
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
36
+ const state = await handleState(event);
36
37
  if (!query.code) {
37
38
  config.scope = config.scope || [];
38
39
  return sendRedirect(
@@ -41,10 +42,14 @@ export function defineOAuthInstagramEventHandler({
41
42
  client_id: config.clientId,
42
43
  redirect_uri: redirectURL,
43
44
  scope: config.scope.join(),
44
- response_type: "code"
45
+ response_type: "code",
46
+ state
45
47
  })
46
48
  );
47
49
  }
50
+ if (query.state !== state) {
51
+ return handleInvalidState(event, "instagram", onError);
52
+ }
48
53
  const tokens = await requestAccessToken(config.tokenURL, {
49
54
  body: {
50
55
  client_id: config.clientId,
@@ -1,7 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
6
  export function defineOAuthKeycloakEventHandler({
7
7
  config,
@@ -30,6 +30,7 @@ export function defineOAuthKeycloakEventHandler({
30
30
  const authorizationURL = `${realmURL}/protocol/openid-connect/auth`;
31
31
  const tokenURL = `${realmURLInternal}/protocol/openid-connect/token`;
32
32
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
33
+ const state = await handleState(event);
33
34
  if (!query.code) {
34
35
  config.scope = config.scope || ["openid"];
35
36
  return sendRedirect(
@@ -40,10 +41,14 @@ export function defineOAuthKeycloakEventHandler({
40
41
  redirect_uri: redirectURL,
41
42
  scope: config.scope.join(" "),
42
43
  response_type: "code",
43
- ...config.authorizationParams
44
+ ...config.authorizationParams,
45
+ state
44
46
  })
45
47
  );
46
48
  }
49
+ if (query.state !== state) {
50
+ return handleInvalidState(event, "keycloak", onError);
51
+ }
47
52
  config.scope = config.scope || [];
48
53
  if (!config.scope.includes("openid")) {
49
54
  config.scope.push("openid");
@@ -1,8 +1,7 @@
1
1
  import { eventHandler, getQuery, sendRedirect } from "h3";
2
2
  import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
- import { randomUUID } from "uncrypto";
5
- import { handleAccessTokenErrorResponse, handleMissingConfiguration, getOAuthRedirectURL, requestAccessToken, handlePkceVerifier } from "../utils.js";
4
+ import { handleAccessTokenErrorResponse, handleInvalidState, handleMissingConfiguration, getOAuthRedirectURL, requestAccessToken, handlePkceVerifier, handleState } from "../utils.js";
6
5
  import { useRuntimeConfig, createError } from "#imports";
7
6
  export function defineOAuthKickEventHandler({ config, onSuccess, onError }) {
8
7
  return eventHandler(async (event) => {
@@ -15,6 +14,7 @@ export function defineOAuthKickEventHandler({ config, onSuccess, onError }) {
15
14
  return handleMissingConfiguration(event, "kick", ["clientId", "clientSecret"], onError);
16
15
  }
17
16
  const verifier = await handlePkceVerifier(event);
17
+ const state = await handleState(event);
18
18
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
19
19
  if (!query.code) {
20
20
  config.scope = config.scope || [];
@@ -27,12 +27,15 @@ export function defineOAuthKickEventHandler({ config, onSuccess, onError }) {
27
27
  client_id: config.clientId,
28
28
  redirect_uri: redirectURL,
29
29
  scope: config.scope.join(" "),
30
- state: randomUUID(),
30
+ state,
31
31
  code_challenge: verifier.code_challenge,
32
32
  code_challenge_method: verifier.code_challenge_method
33
33
  })
34
34
  );
35
35
  }
36
+ if (query.state !== state) {
37
+ return handleInvalidState(event, "kick", onError);
38
+ }
36
39
  const tokens = await requestAccessToken(config.tokenURL, {
37
40
  body: {
38
41
  grant_type: "authorization_code",