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.
- package/README.md +239 -4
- package/dist/module.d.mts +22 -0
- package/dist/module.d.ts +22 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +40 -2
- package/dist/runtime/app/composables/webauthn.d.ts +13 -0
- package/dist/runtime/app/composables/webauthn.js +62 -0
- package/dist/runtime/server/api/session.get.js +1 -1
- package/dist/runtime/server/lib/oauth/auth0.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/auth0.js +1 -1
- package/dist/runtime/server/lib/oauth/battledotnet.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/battledotnet.js +1 -1
- package/dist/runtime/server/lib/oauth/cognito.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/cognito.js +1 -1
- package/dist/runtime/server/lib/oauth/discord.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/discord.js +1 -1
- package/dist/runtime/server/lib/oauth/dropbox.d.ts +47 -0
- package/dist/runtime/server/lib/oauth/dropbox.js +72 -0
- package/dist/runtime/server/lib/oauth/facebook.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/facebook.js +1 -1
- package/dist/runtime/server/lib/oauth/github.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/github.js +1 -1
- package/dist/runtime/server/lib/oauth/gitlab.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/gitlab.js +1 -1
- package/dist/runtime/server/lib/oauth/google.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/google.js +2 -1
- package/dist/runtime/server/lib/oauth/instagram.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/instagram.js +1 -1
- package/dist/runtime/server/lib/oauth/keycloak.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/keycloak.js +1 -1
- package/dist/runtime/server/lib/oauth/linkedin.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/linkedin.js +1 -1
- package/dist/runtime/server/lib/oauth/microsoft.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/microsoft.js +1 -1
- package/dist/runtime/server/lib/oauth/paypal.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/paypal.js +1 -1
- package/dist/runtime/server/lib/oauth/spotify.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/spotify.js +1 -1
- package/dist/runtime/server/lib/oauth/steam.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/steam.js +11 -8
- package/dist/runtime/server/lib/oauth/tiktok.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/tiktok.js +1 -1
- package/dist/runtime/server/lib/oauth/twitch.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/twitch.js +1 -1
- package/dist/runtime/server/lib/oauth/vk.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/vk.js +1 -1
- package/dist/runtime/server/lib/oauth/x.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/x.js +1 -1
- package/dist/runtime/server/lib/oauth/xsuaa.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/xsuaa.js +1 -1
- package/dist/runtime/server/lib/oauth/yandex.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/yandex.js +1 -1
- package/dist/runtime/server/lib/webauthn/authenticate.d.ts +5 -0
- package/dist/runtime/server/lib/webauthn/authenticate.js +73 -0
- package/dist/runtime/server/lib/webauthn/register.d.ts +7 -0
- package/dist/runtime/server/lib/webauthn/register.js +116 -0
- package/dist/runtime/server/lib/webauthn/utils.d.ts +3 -0
- package/dist/runtime/server/lib/webauthn/utils.js +35 -0
- package/dist/runtime/server/utils/password.d.ts +23 -0
- package/dist/runtime/server/utils/password.js +18 -0
- package/dist/runtime/types/index.d.ts +1 -0
- package/dist/runtime/types/oauth-config.d.ts +1 -1
- package/dist/runtime/types/webauthn.d.ts +76 -0
- package/dist/runtime/types/webauthn.js +0 -0
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
47
|
+
export declare function defineOAuthGitLabEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthGitLabConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
@@ -44,4 +44,4 @@ export interface OAuthGoogleConfig {
|
|
|
44
44
|
*/
|
|
45
45
|
redirectURL?: string;
|
|
46
46
|
}
|
|
47
|
-
export declare function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
46
|
+
export declare function defineOAuthVKEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthVKConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
@@ -43,4 +43,4 @@ export interface OAuthXConfig {
|
|
|
43
43
|
*/
|
|
44
44
|
redirectURL?: string;
|
|
45
45
|
}
|
|
46
|
-
export declare function
|
|
46
|
+
export declare function defineOAuthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
@@ -28,4 +28,4 @@ export interface OAuthXSUAAConfig {
|
|
|
28
28
|
*/
|
|
29
29
|
redirectURL?: string;
|
|
30
30
|
}
|
|
31
|
-
export declare function
|
|
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
|
|
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
|
|
46
|
+
export declare function defineOAuthYandexEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthYandexConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
|
|
@@ -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
|
+
}
|