nuxt-auth-utils 0.3.9 → 0.4.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.
Files changed (65) hide show
  1. package/README.md +239 -4
  2. package/dist/module.d.mts +22 -0
  3. package/dist/module.d.ts +22 -0
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +40 -2
  6. package/dist/runtime/app/composables/webauthn.d.ts +13 -0
  7. package/dist/runtime/app/composables/webauthn.js +62 -0
  8. package/dist/runtime/server/api/session.get.js +1 -1
  9. package/dist/runtime/server/lib/oauth/auth0.d.ts +1 -1
  10. package/dist/runtime/server/lib/oauth/auth0.js +1 -1
  11. package/dist/runtime/server/lib/oauth/battledotnet.d.ts +1 -1
  12. package/dist/runtime/server/lib/oauth/battledotnet.js +1 -1
  13. package/dist/runtime/server/lib/oauth/cognito.d.ts +1 -1
  14. package/dist/runtime/server/lib/oauth/cognito.js +1 -1
  15. package/dist/runtime/server/lib/oauth/discord.d.ts +1 -1
  16. package/dist/runtime/server/lib/oauth/discord.js +1 -1
  17. package/dist/runtime/server/lib/oauth/dropbox.d.ts +47 -0
  18. package/dist/runtime/server/lib/oauth/dropbox.js +72 -0
  19. package/dist/runtime/server/lib/oauth/facebook.d.ts +1 -1
  20. package/dist/runtime/server/lib/oauth/facebook.js +1 -1
  21. package/dist/runtime/server/lib/oauth/github.d.ts +1 -1
  22. package/dist/runtime/server/lib/oauth/github.js +1 -1
  23. package/dist/runtime/server/lib/oauth/gitlab.d.ts +1 -1
  24. package/dist/runtime/server/lib/oauth/gitlab.js +1 -1
  25. package/dist/runtime/server/lib/oauth/google.d.ts +1 -1
  26. package/dist/runtime/server/lib/oauth/google.js +2 -1
  27. package/dist/runtime/server/lib/oauth/instagram.d.ts +1 -1
  28. package/dist/runtime/server/lib/oauth/instagram.js +1 -1
  29. package/dist/runtime/server/lib/oauth/keycloak.d.ts +1 -1
  30. package/dist/runtime/server/lib/oauth/keycloak.js +1 -1
  31. package/dist/runtime/server/lib/oauth/linkedin.d.ts +1 -1
  32. package/dist/runtime/server/lib/oauth/linkedin.js +1 -1
  33. package/dist/runtime/server/lib/oauth/microsoft.d.ts +1 -1
  34. package/dist/runtime/server/lib/oauth/microsoft.js +1 -1
  35. package/dist/runtime/server/lib/oauth/paypal.d.ts +1 -1
  36. package/dist/runtime/server/lib/oauth/paypal.js +1 -1
  37. package/dist/runtime/server/lib/oauth/spotify.d.ts +1 -1
  38. package/dist/runtime/server/lib/oauth/spotify.js +1 -1
  39. package/dist/runtime/server/lib/oauth/steam.d.ts +1 -1
  40. package/dist/runtime/server/lib/oauth/steam.js +11 -8
  41. package/dist/runtime/server/lib/oauth/tiktok.d.ts +1 -1
  42. package/dist/runtime/server/lib/oauth/tiktok.js +1 -1
  43. package/dist/runtime/server/lib/oauth/twitch.d.ts +1 -1
  44. package/dist/runtime/server/lib/oauth/twitch.js +1 -1
  45. package/dist/runtime/server/lib/oauth/vk.d.ts +1 -1
  46. package/dist/runtime/server/lib/oauth/vk.js +1 -1
  47. package/dist/runtime/server/lib/oauth/x.d.ts +1 -1
  48. package/dist/runtime/server/lib/oauth/x.js +1 -1
  49. package/dist/runtime/server/lib/oauth/xsuaa.d.ts +1 -1
  50. package/dist/runtime/server/lib/oauth/xsuaa.js +1 -1
  51. package/dist/runtime/server/lib/oauth/yandex.d.ts +1 -1
  52. package/dist/runtime/server/lib/oauth/yandex.js +1 -1
  53. package/dist/runtime/server/lib/webauthn/authenticate.d.ts +5 -0
  54. package/dist/runtime/server/lib/webauthn/authenticate.js +73 -0
  55. package/dist/runtime/server/lib/webauthn/register.d.ts +7 -0
  56. package/dist/runtime/server/lib/webauthn/register.js +116 -0
  57. package/dist/runtime/server/lib/webauthn/utils.d.ts +3 -0
  58. package/dist/runtime/server/lib/webauthn/utils.js +35 -0
  59. package/dist/runtime/server/utils/password.d.ts +23 -0
  60. package/dist/runtime/server/utils/password.js +18 -0
  61. package/dist/runtime/types/index.d.ts +1 -0
  62. package/dist/runtime/types/oauth-config.d.ts +1 -1
  63. package/dist/runtime/types/webauthn.d.ts +76 -0
  64. package/dist/runtime/types/webauthn.js +0 -0
  65. package/package.json +23 -9
@@ -0,0 +1,72 @@
1
+ import { eventHandler, getQuery, sendRedirect } from "h3";
2
+ import { withQuery } from "ufo";
3
+ import { defu } from "defu";
4
+ import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
+ import { useRuntimeConfig, createError } from "#imports";
6
+ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
7
+ return eventHandler(async (event) => {
8
+ config = defu(config, useRuntimeConfig(event).oauth?.dropbox, {
9
+ authorizationURL: "https://www.dropbox.com/oauth2/authorize",
10
+ tokenURL: "https://api.dropboxapi.com/oauth2/token",
11
+ authorizationParams: {}
12
+ });
13
+ const query = getQuery(event);
14
+ if (!config.clientId) {
15
+ return handleMissingConfiguration(event, "dropbox", ["clientId"], onError);
16
+ }
17
+ const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
18
+ if (!query.code) {
19
+ config.scope = config.scope || [];
20
+ if (!config.scope.includes("openid")) {
21
+ config.scope.push("openid");
22
+ }
23
+ if (config.emailRequired && !config.scope.includes("email")) {
24
+ config.scope.push("email");
25
+ }
26
+ return sendRedirect(
27
+ event,
28
+ withQuery(config.authorizationURL, {
29
+ response_type: "code",
30
+ client_id: config.clientId,
31
+ redirect_uri: redirectURL,
32
+ scope: config.scope.join(" "),
33
+ ...config.authorizationParams
34
+ })
35
+ );
36
+ }
37
+ const tokens = await requestAccessToken(config.tokenURL, {
38
+ headers: {
39
+ Authorization: `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`
40
+ },
41
+ params: {
42
+ grant_type: "authorization_code",
43
+ redirect_uri: redirectURL,
44
+ code: query.code
45
+ }
46
+ });
47
+ if (tokens.error) {
48
+ return handleAccessTokenErrorResponse(event, "dropbox", tokens, onError);
49
+ }
50
+ const accessToken = tokens.access_token;
51
+ const users = await $fetch("https://api.dropboxapi.com/2/openid/userinfo", {
52
+ method: "POST",
53
+ headers: {
54
+ Authorization: `Bearer ${accessToken}`
55
+ }
56
+ });
57
+ const user = users;
58
+ if (!user) {
59
+ const error = createError({
60
+ statusCode: 500,
61
+ message: "Could not get Dropbox user",
62
+ data: tokens
63
+ });
64
+ if (!onError) throw error;
65
+ return onError(event, error);
66
+ }
67
+ return onSuccess(event, {
68
+ tokens,
69
+ user
70
+ });
71
+ });
72
+ }
@@ -45,4 +45,4 @@ export interface OAuthFacebookConfig {
45
45
  */
46
46
  redirectURL?: string;
47
47
  }
48
- export declare function oauthFacebookEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthFacebookConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
48
+ export declare function defineOAuthFacebookEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthFacebookConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthFacebookEventHandler({
6
+ export function defineOAuthFacebookEventHandler({
7
7
  config,
8
8
  onSuccess,
9
9
  onError
@@ -45,4 +45,4 @@ export interface OAuthGitHubConfig {
45
45
  */
46
46
  redirectURL?: string;
47
47
  }
48
- export declare function oauthGitHubEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthGitHubConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
48
+ export declare function defineOAuthGitHubEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthGitHubConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthGitHubEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthGitHubEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.github, {
9
9
  authorizationURL: "https://github.com/login/oauth/authorize",
@@ -44,4 +44,4 @@ export interface OAuthGitLabConfig {
44
44
  */
45
45
  redirectURL?: string;
46
46
  }
47
- export declare function oauthGitLabEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthGitLabConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
47
+ export declare function defineOAuthGitLabEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthGitLabConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -8,7 +8,7 @@ import {
8
8
  requestAccessToken
9
9
  } from "../utils.js";
10
10
  import { useRuntimeConfig, createError } from "#imports";
11
- export function oauthGitLabEventHandler({
11
+ export function defineOAuthGitLabEventHandler({
12
12
  config,
13
13
  onSuccess,
14
14
  onError
@@ -44,4 +44,4 @@ export interface OAuthGoogleConfig {
44
44
  */
45
45
  redirectURL?: string;
46
46
  }
47
- export declare function oauthGoogleEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthGoogleConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
47
+ export declare function defineOAuthGoogleEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthGoogleConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function oauthGoogleEventHandler({
6
+ export function defineOAuthGoogleEventHandler({
7
7
  config,
8
8
  onSuccess,
9
9
  onError
@@ -29,6 +29,7 @@ export function oauthGoogleEventHandler({
29
29
  client_id: config.clientId,
30
30
  redirect_uri: redirectURL,
31
31
  scope: config.scope.join(" "),
32
+ state: query.state || "",
32
33
  ...config.authorizationParams
33
34
  })
34
35
  );
@@ -45,4 +45,4 @@ export interface OAuthInstagramConfig {
45
45
  */
46
46
  redirectURL?: string;
47
47
  }
48
- export declare function oauthInstagramEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthInstagramConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
48
+ export declare function defineOAuthInstagramEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthInstagramConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthInstagramEventHandler({
6
+ export function defineOAuthInstagramEventHandler({
7
7
  config,
8
8
  onSuccess,
9
9
  onError
@@ -38,4 +38,4 @@ export interface OAuthKeycloakConfig {
38
38
  */
39
39
  redirectURL?: string;
40
40
  }
41
- export declare function oauthKeycloakEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthKeycloakConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
41
+ export declare function defineOAuthKeycloakEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthKeycloakConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthKeycloakEventHandler({
6
+ export function defineOAuthKeycloakEventHandler({
7
7
  config,
8
8
  onSuccess,
9
9
  onError
@@ -42,4 +42,4 @@ export interface OAuthLinkedInConfig {
42
42
  */
43
43
  redirectURL?: string;
44
44
  }
45
- export declare function oauthLinkedInEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinkedInConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
45
+ export declare function defineOAuthLinkedInEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinkedInConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function oauthLinkedInEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthLinkedInEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.linkedin, {
9
9
  authorizationURL: "https://www.linkedin.com/oauth/v2/authorization",
@@ -51,4 +51,4 @@ export interface OAuthMicrosoftConfig {
51
51
  */
52
52
  redirectURL?: string;
53
53
  }
54
- export declare function oauthMicrosoftEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthMicrosoftConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
54
+ export declare function defineOAuthMicrosoftEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthMicrosoftConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthMicrosoftEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthMicrosoftEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.microsoft, {
9
9
  authorizationParams: {}
@@ -49,4 +49,4 @@ export interface OAuthPaypalConfig {
49
49
  */
50
50
  redirectURL?: string;
51
51
  }
52
- export declare function oauthPaypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
52
+ export declare function defineOAuthPaypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthPaypalEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthPaypalEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.paypal, {
9
9
  sandbox: import.meta.dev,
@@ -44,4 +44,4 @@ export interface OAuthSpotifyConfig {
44
44
  */
45
45
  redirectURL?: string;
46
46
  }
47
- export declare function oauthSpotifyEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSpotifyConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
47
+ export declare function defineOAuthSpotifyEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSpotifyConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function oauthSpotifyEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthSpotifyEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.spotify, {
9
9
  authorizationURL: "https://accounts.spotify.com/authorize",
@@ -17,4 +17,4 @@ export interface OAuthSteamConfig {
17
17
  */
18
18
  redirectURL?: string;
19
19
  }
20
- export declare function oauthSteamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSteamConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
20
+ export declare function defineOAuthSteamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSteamConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function oauthSteamEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthSteamEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.steam, {
9
9
  authorizationURL: "https://steamcommunity.com/openid/login"
@@ -23,19 +23,22 @@ export function oauthSteamEventHandler({ config, onSuccess, onError }) {
23
23
  };
24
24
  return sendRedirect(event, withQuery(config.authorizationURL, steamOpenIdParams));
25
25
  }
26
- const validateAuth = await $fetch(withQuery(config.authorizationURL, {
27
- ...query,
28
- "openid.mode": "check_authentication"
29
- }));
30
- if (!validateAuth.includes("is_valid:true")) {
26
+ const openIdCheck = {
27
+ ns: "http://specs.openid.net/auth/2.0",
28
+ claimed_id: "https://steamcommunity.com/openid/id/",
29
+ identity: "https://steamcommunity.com/openid/id/"
30
+ };
31
+ const idRegex = /^https?:\/\/steamcommunity\.com\/openid\/id\/(\d+)$/;
32
+ const steamIdCheck = idRegex.exec(query["openid.claimed_id"]);
33
+ if (query["openid.op_endpoint"] !== config.authorizationURL || !steamIdCheck || query["openid.ns"] !== openIdCheck.ns || !query["openid.claimed_id"]?.startsWith(openIdCheck.claimed_id) || !query["openid.identity"]?.startsWith(openIdCheck.identity)) {
31
34
  const error = createError({
32
35
  statusCode: 401,
33
- message: "Steam login failed: Unknown error"
36
+ message: "Steam login failed: Claimed identity is invalid."
34
37
  });
35
38
  if (!onError) throw error;
36
39
  return onError(event, error);
37
40
  }
38
- const steamId = query["openid.claimed_id"].split("/").pop();
41
+ const steamId = steamIdCheck[1];
39
42
  const user = await $fetch(withQuery("https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/", {
40
43
  key: config.apiKey,
41
44
  steamids: steamId
@@ -42,4 +42,4 @@ export interface OAuthTikTokConfig {
42
42
  */
43
43
  redirectURL?: string;
44
44
  }
45
- export declare function oauthTikTokEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTikTokConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
45
+ export declare function defineOAuthTikTokEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTikTokConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -4,7 +4,7 @@ import { defu } from "defu";
4
4
  import { sha256 } from "ohash";
5
5
  import { handleAccessTokenErrorResponse, handleMissingConfiguration, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
6
6
  import { useRuntimeConfig, createError } from "#imports";
7
- export function oauthTikTokEventHandler({ config, onSuccess, onError }) {
7
+ export function defineOAuthTikTokEventHandler({ config, onSuccess, onError }) {
8
8
  return eventHandler(async (event) => {
9
9
  config = defu(config, useRuntimeConfig(event).oauth?.tiktok, {
10
10
  sandbox: import.meta.dev,
@@ -44,4 +44,4 @@ export interface OAuthTwitchConfig {
44
44
  */
45
45
  redirectURL?: string;
46
46
  }
47
- export declare function oauthTwitchEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTwitchConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
47
+ export declare function defineOAuthTwitchEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTwitchConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig, createError } from "#imports";
6
- export function oauthTwitchEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthTwitchEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.twitch, {
9
9
  authorizationURL: "https://id.twitch.tv/oauth2/authorize",
@@ -43,4 +43,4 @@ export interface OAuthVKConfig {
43
43
  */
44
44
  redirectURL?: string;
45
45
  }
46
- export declare function oauthVKEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthVKConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
46
+ export declare function defineOAuthVKEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthVKConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -9,7 +9,7 @@ import {
9
9
  requestAccessToken
10
10
  } from "../utils.js";
11
11
  import { useRuntimeConfig, createError } from "#imports";
12
- export function oauthVKEventHandler({
12
+ export function defineOAuthVKEventHandler({
13
13
  config,
14
14
  onSuccess,
15
15
  onError
@@ -43,4 +43,4 @@ export interface OAuthXConfig {
43
43
  */
44
44
  redirectURL?: string;
45
45
  }
46
- export declare function oauthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
46
+ export declare function defineOAuthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -9,7 +9,7 @@ import {
9
9
  requestAccessToken
10
10
  } from "../utils.js";
11
11
  import { useRuntimeConfig } from "#imports";
12
- export function oauthXEventHandler({
12
+ export function defineOAuthXEventHandler({
13
13
  config,
14
14
  onSuccess,
15
15
  onError
@@ -28,4 +28,4 @@ export interface OAuthXSUAAConfig {
28
28
  */
29
29
  redirectURL?: string;
30
30
  }
31
- export declare function oauthXSUAAEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthXSUAAConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
31
+ export declare function defineOAuthXSUAAEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthXSUAAConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,7 +3,7 @@ import { withQuery } from "ufo";
3
3
  import { defu } from "defu";
4
4
  import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function oauthXSUAAEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthXSUAAEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
8
  config = defu(config, useRuntimeConfig(event).oauth?.xsuaa);
9
9
  const query = getQuery(event);
@@ -43,4 +43,4 @@ export interface OAuthYandexConfig {
43
43
  */
44
44
  redirectURL?: string;
45
45
  }
46
- export declare function oauthYandexEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthYandexConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
46
+ export declare function defineOAuthYandexEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthYandexConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -8,7 +8,7 @@ import {
8
8
  requestAccessToken
9
9
  } from "../utils.js";
10
10
  import { useRuntimeConfig } from "#imports";
11
- export function oauthYandexEventHandler({
11
+ export function defineOAuthYandexEventHandler({
12
12
  config,
13
13
  onSuccess,
14
14
  onError
@@ -0,0 +1,5 @@
1
+ import type { WebAuthnAuthenticateEventHandlerOptions, WebAuthnCredential } from '#auth-utils';
2
+ export declare function defineWebAuthnAuthenticateEventHandler<T extends WebAuthnCredential>({ storeChallenge, getChallenge, getCredential, allowCredentials, getOptions, onSuccess, onError, }: WebAuthnAuthenticateEventHandlerOptions<T>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void | import("@simplewebauthn/server").VerifiedAuthenticationResponse | {
3
+ requestOptions: import("@simplewebauthn/types").PublicKeyCredentialRequestOptionsJSON;
4
+ attemptId: string;
5
+ }>>;
@@ -0,0 +1,73 @@
1
+ import { eventHandler, H3Error, createError, getRequestURL, readBody } from "h3";
2
+ import { generateAuthenticationOptions, verifyAuthenticationResponse } from "@simplewebauthn/server";
3
+ import defu from "defu";
4
+ import { getRandomValues } from "uncrypto";
5
+ import { base64URLStringToBuffer, bufferToBase64URLString } from "@simplewebauthn/browser";
6
+ import { storeChallengeAsSession, getChallengeFromSession } from "./utils.js";
7
+ import { useRuntimeConfig } from "#imports";
8
+ export function defineWebAuthnAuthenticateEventHandler({
9
+ storeChallenge,
10
+ getChallenge,
11
+ getCredential,
12
+ allowCredentials,
13
+ getOptions,
14
+ onSuccess,
15
+ onError
16
+ }) {
17
+ return eventHandler(async (event) => {
18
+ const url = getRequestURL(event);
19
+ const body = await readBody(event);
20
+ const _config = defu(await getOptions?.(event) ?? {}, useRuntimeConfig(event).webauthn.authenticate, {
21
+ rpID: url.hostname
22
+ });
23
+ if (allowCredentials && body.userName) {
24
+ _config.allowCredentials = await allowCredentials(event, body.userName);
25
+ }
26
+ try {
27
+ if (!body.verify) {
28
+ const options = await generateAuthenticationOptions(_config);
29
+ const attemptId = bufferToBase64URLString(getRandomValues(new Uint8Array(32)));
30
+ if (storeChallenge)
31
+ await storeChallenge(event, options.challenge, attemptId);
32
+ else
33
+ await storeChallengeAsSession(event, options.challenge, attemptId);
34
+ return {
35
+ requestOptions: options,
36
+ attemptId
37
+ };
38
+ }
39
+ if (!body.attemptId)
40
+ throw createError({ statusCode: 400 });
41
+ let challenge;
42
+ if (getChallenge)
43
+ challenge = await getChallenge(event, body.attemptId);
44
+ else
45
+ challenge = await getChallengeFromSession(event, body.attemptId);
46
+ const credential = await getCredential(event, body.response.id);
47
+ const verification = await verifyAuthenticationResponse({
48
+ response: body.response,
49
+ expectedChallenge: challenge,
50
+ expectedOrigin: url.origin,
51
+ expectedRPID: url.hostname,
52
+ authenticator: {
53
+ credentialID: credential.id,
54
+ credentialPublicKey: new Uint8Array(base64URLStringToBuffer(credential.publicKey)),
55
+ counter: credential.counter,
56
+ transports: credential.transports
57
+ }
58
+ });
59
+ if (!verification.verified)
60
+ throw createError({ statusCode: 400, message: "Failed to verify registration response" });
61
+ await onSuccess(event, {
62
+ credential,
63
+ authenticationInfo: verification.authenticationInfo
64
+ });
65
+ return verification;
66
+ } catch (error) {
67
+ if (!onError) throw error;
68
+ if (error instanceof H3Error)
69
+ return onError(event, error);
70
+ return onError(event, createError({ statusCode: 500, message: "Failed to authenticate credential" }));
71
+ }
72
+ });
73
+ }
@@ -0,0 +1,7 @@
1
+ import type { ValidateFunction } from 'h3';
2
+ import type { WebAuthnUser, WebAuthnRegisterEventHandlerOptions } from '#auth-utils';
3
+ export declare function defineWebAuthnRegisterEventHandler<T extends WebAuthnUser>({ storeChallenge, getChallenge, getOptions, validateUser, onSuccess, onError, }: WebAuthnRegisterEventHandlerOptions<T>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void | import("@simplewebauthn/server").VerifiedRegistrationResponse | {
4
+ creationOptions: import("@simplewebauthn/types").PublicKeyCredentialCreationOptionsJSON;
5
+ attemptId: string;
6
+ }>>;
7
+ export declare function validateUserData<T>(data: unknown, fn: ValidateFunction<T>): Promise<T>;
@@ -0,0 +1,116 @@
1
+ import { eventHandler, H3Error, createError, getRequestURL, readBody } from "h3";
2
+ import { generateRegistrationOptions, verifyRegistrationResponse } from "@simplewebauthn/server";
3
+ import defu from "defu";
4
+ import { bufferToBase64URLString } from "@simplewebauthn/browser";
5
+ import { getRandomValues } from "uncrypto";
6
+ import { storeChallengeAsSession, getChallengeFromSession } from "./utils.js";
7
+ import { useRuntimeConfig } from "#imports";
8
+ export function defineWebAuthnRegisterEventHandler({
9
+ storeChallenge,
10
+ getChallenge,
11
+ getOptions,
12
+ validateUser,
13
+ onSuccess,
14
+ onError
15
+ }) {
16
+ return eventHandler(async (event) => {
17
+ const url = getRequestURL(event);
18
+ const body = await readBody(event);
19
+ if (body.verify === void 0 || !body.user?.userName)
20
+ throw createError({
21
+ message: "Invalid request, missing userName or verify property",
22
+ statusCode: 400
23
+ });
24
+ let user = body.user;
25
+ if (validateUser) {
26
+ user = await validateUserData(body.user, validateUser);
27
+ }
28
+ const _config = defu(await getOptions?.(event) ?? {}, useRuntimeConfig(event).webauthn.register, {
29
+ rpID: url.hostname,
30
+ rpName: url.hostname,
31
+ userName: user.userName,
32
+ userDisplayName: user.displayName,
33
+ authenticatorSelection: {
34
+ userVerification: "preferred"
35
+ }
36
+ });
37
+ try {
38
+ if (!body.verify) {
39
+ const options = await generateRegistrationOptions(_config);
40
+ const attemptId = bufferToBase64URLString(getRandomValues(new Uint8Array(32)));
41
+ if (storeChallenge)
42
+ await storeChallenge?.(event, options.challenge, attemptId);
43
+ else
44
+ await storeChallengeAsSession(event, options.challenge, attemptId);
45
+ return {
46
+ creationOptions: options,
47
+ attemptId
48
+ };
49
+ }
50
+ if (!body.attemptId) {
51
+ throw createError({
52
+ message: "Invalid request, missing attemptId",
53
+ statusCode: 400
54
+ });
55
+ }
56
+ let expectedChallenge;
57
+ if (getChallenge)
58
+ expectedChallenge = await getChallenge(event, body.attemptId);
59
+ else
60
+ expectedChallenge = await getChallengeFromSession(event, body.attemptId);
61
+ const verification = await verifyRegistrationResponse({
62
+ response: body.response,
63
+ expectedChallenge,
64
+ expectedOrigin: url.origin,
65
+ expectedRPID: url.hostname,
66
+ requireUserVerification: false,
67
+ // TODO: make configurable https://simplewebauthn.dev/docs/advanced/passkeys#verifyregistrationresponse
68
+ supportedAlgorithmIDs: _config.supportedAlgorithmIDs
69
+ });
70
+ if (!verification.verified) {
71
+ throw createError({
72
+ message: "Failed to verify registration response",
73
+ statusCode: 400
74
+ });
75
+ }
76
+ await onSuccess(event, {
77
+ user,
78
+ credential: {
79
+ id: verification.registrationInfo.credentialID,
80
+ publicKey: bufferToBase64URLString(verification.registrationInfo.credentialPublicKey),
81
+ counter: verification.registrationInfo.counter,
82
+ backedUp: verification.registrationInfo.credentialBackedUp,
83
+ transports: body.response.response.transports
84
+ },
85
+ registrationInfo: verification.registrationInfo
86
+ });
87
+ return verification;
88
+ } catch (error) {
89
+ if (!onError) throw error;
90
+ if (error instanceof H3Error)
91
+ return onError(event, error);
92
+ return onError(event, createError({ statusCode: 500, message: "Failed to register credential" }));
93
+ }
94
+ });
95
+ }
96
+ export async function validateUserData(data, fn) {
97
+ try {
98
+ const res = await fn(data);
99
+ if (res === false) {
100
+ throw createUserValidationError();
101
+ }
102
+ if (res === true) {
103
+ return data;
104
+ }
105
+ return res ?? data;
106
+ } catch (error) {
107
+ throw createUserValidationError(error);
108
+ }
109
+ }
110
+ function createUserValidationError(validateError) {
111
+ throw createError({
112
+ status: 400,
113
+ message: "User Validation Error",
114
+ data: validateError
115
+ });
116
+ }
@@ -0,0 +1,3 @@
1
+ import { type H3Event } from 'h3';
2
+ export declare function storeChallengeAsSession(event: H3Event, challenge: string, challengeId: string): Promise<void>;
3
+ export declare function getChallengeFromSession(event: H3Event, challengeId: string): Promise<string>;