nuxt-auth-utils 0.5.32 → 0.5.33
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 +55 -4
- package/dist/module.json +1 -1
- package/dist/module.mjs +19 -1
- package/dist/runtime/app/composables/session.js +8 -3
- package/dist/runtime/app/plugins/session.client.js +8 -4
- package/dist/runtime/server/api/session.delete.d.ts +3 -1
- package/dist/runtime/server/api/session.get.d.ts +1 -1
- package/dist/runtime/server/lib/atproto/bluesky.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/apple.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/apple.js +3 -0
- package/dist/runtime/server/lib/oauth/atlassian.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/auth0.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/authentik.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/azureb2c.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/battledotnet.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/box.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/cloudflare.d.ts +86 -0
- package/dist/runtime/server/lib/oauth/cloudflare.js +72 -0
- package/dist/runtime/server/lib/oauth/cognito.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/discord.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/dropbox.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/facebook.d.ts +14 -3
- package/dist/runtime/server/lib/oauth/facebook.js +15 -3
- package/dist/runtime/server/lib/oauth/gitea.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/github.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/gitlab.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/google.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/heroku.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/hubspot.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/instagram.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/keycloak.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/kick.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/line.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/linear.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/linkedin.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/livechat.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/mastodon.d.ts +62 -0
- package/dist/runtime/server/lib/oauth/mastodon.js +178 -0
- package/dist/runtime/server/lib/oauth/microsoft.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/oidc.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/oidc.js +4 -3
- package/dist/runtime/server/lib/oauth/okta.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/ory.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/osu.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/paypal.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/polar.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/riotgames.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/roblox.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/salesforce.d.ts +9 -4
- package/dist/runtime/server/lib/oauth/salesforce.js +8 -4
- package/dist/runtime/server/lib/oauth/seznam.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/shopifyCustomer.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/shopifyCustomer.js +1 -1
- package/dist/runtime/server/lib/oauth/slack.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/spotify.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/steam.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/strava.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/tiktok.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/twitch.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/vk.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/wechat.d.ts +67 -0
- package/dist/runtime/server/lib/oauth/wechat.js +107 -0
- package/dist/runtime/server/lib/oauth/workos.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/x.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/xsuaa.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/yandex.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/zitadel.d.ts +1 -1
- package/dist/runtime/server/lib/utils.d.ts +4 -3
- package/dist/runtime/server/lib/utils.js +3 -3
- package/dist/runtime/server/routes/atproto/client-metadata.json.get.d.ts +128 -1
- package/dist/runtime/server/utils/session.js +6 -1
- package/dist/runtime/types/oauth-config.d.ts +1 -1
- package/package.json +12 -16
|
@@ -42,4 +42,4 @@ export interface OAuthLineConfig {
|
|
|
42
42
|
*/
|
|
43
43
|
redirectURL?: string;
|
|
44
44
|
}
|
|
45
|
-
export declare function defineOAuthLineEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthLineConfig>): any
|
|
45
|
+
export declare function defineOAuthLineEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthLineConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -38,4 +38,4 @@ export interface OAuthLinearConfig {
|
|
|
38
38
|
*/
|
|
39
39
|
redirectURL?: string;
|
|
40
40
|
}
|
|
41
|
-
export declare function defineOAuthLinearEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinearConfig>): any
|
|
41
|
+
export declare function defineOAuthLinearEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinearConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -42,4 +42,4 @@ export interface OAuthLinkedInConfig {
|
|
|
42
42
|
*/
|
|
43
43
|
redirectURL?: string;
|
|
44
44
|
}
|
|
45
|
-
export declare function defineOAuthLinkedInEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinkedInConfig>): any
|
|
45
|
+
export declare function defineOAuthLinkedInEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthLinkedInConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -70,4 +70,4 @@ export interface LiveChatConfig {
|
|
|
70
70
|
*/
|
|
71
71
|
authorizationParams?: Record<string, string>;
|
|
72
72
|
}
|
|
73
|
-
export declare function defineOAuthLiveChatEventHandler({ config, onSuccess, onError, }: OAuthConfig<LiveChatConfig>): any
|
|
73
|
+
export declare function defineOAuthLiveChatEventHandler({ config, onSuccess, onError, }: OAuthConfig<LiveChatConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthMastodonConfig {
|
|
3
|
+
/**
|
|
4
|
+
* The instance domain to authenticate against, e.g. `mastodon.social`.
|
|
5
|
+
*
|
|
6
|
+
* Unlike most OAuth providers, a Mastodon account lives on a single instance and there is no
|
|
7
|
+
* shared authorization server, so the instance must be known before the flow can start. If not
|
|
8
|
+
* set here, it can be provided at runtime as an `instance` query parameter on the initial request
|
|
9
|
+
* (e.g. `/auth/mastodon?instance=mastodon.social`). A full handle such as `@user@mastodon.social`
|
|
10
|
+
* or `user@mastodon.social` is also accepted, only the domain part is used.
|
|
11
|
+
* @default process.env.NUXT_OAUTH_MASTODON_INSTANCE
|
|
12
|
+
* @example 'mastodon.social'
|
|
13
|
+
*/
|
|
14
|
+
instance?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The name of the application shown to users on the instance's authorization screen.
|
|
17
|
+
*
|
|
18
|
+
* Mastodon has no concept of a pre-registered, shared client id: an application must be
|
|
19
|
+
* registered against every instance it authenticates users on (`POST /api/v1/apps`). This is
|
|
20
|
+
* that application's display name.
|
|
21
|
+
* @default 'Nuxt Auth Utils'
|
|
22
|
+
*/
|
|
23
|
+
clientName?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Mastodon OAuth Scope.
|
|
26
|
+
* @default ['read']
|
|
27
|
+
* @see https://docs.joinmastodon.org/api/oauth-scopes/
|
|
28
|
+
* @example ['read', 'read:accounts']
|
|
29
|
+
*/
|
|
30
|
+
scope?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Redirect URL to allow overriding for situations like prod failing to determine public hostname
|
|
33
|
+
* @default process.env.NUXT_OAUTH_MASTODON_REDIRECT_URL or current URL
|
|
34
|
+
*/
|
|
35
|
+
redirectURL?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface OAuthMastodonUser {
|
|
38
|
+
id: string;
|
|
39
|
+
username: string;
|
|
40
|
+
/**
|
|
41
|
+
* Always the full `user@instance` handle here, even for the authenticated user's own account.
|
|
42
|
+
* Mastodon's API normally only qualifies `acct` with `@instance` for remote accounts and returns
|
|
43
|
+
* the bare username for your own, we normalize it since an account only means something together
|
|
44
|
+
* with the instance it lives on.
|
|
45
|
+
*/
|
|
46
|
+
acct: string;
|
|
47
|
+
display_name: string;
|
|
48
|
+
url: string;
|
|
49
|
+
avatar: string;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
interface MastodonTokens {
|
|
53
|
+
access_token: string;
|
|
54
|
+
token_type: string;
|
|
55
|
+
scope: string;
|
|
56
|
+
created_at: number;
|
|
57
|
+
}
|
|
58
|
+
export declare function defineOAuthMastodonEventHandler<TUser = OAuthMastodonUser>({ config: userConfig, onSuccess, onError }: OAuthConfig<OAuthMastodonConfig, {
|
|
59
|
+
user: TUser;
|
|
60
|
+
tokens: MastodonTokens;
|
|
61
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { createError, deleteCookie, eventHandler, getCookie, getQuery, sendRedirect, setCookie } from "h3";
|
|
2
|
+
import { withQuery } from "ufo";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { $fetch } from "ofetch";
|
|
5
|
+
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleInvalidState, handleState, isDevelopment, requestAccessToken } from "../utils.js";
|
|
6
|
+
import { useRuntimeConfig } from "#imports";
|
|
7
|
+
const FLOW_COOKIE_NAME = "nuxt-auth-mastodon-flow";
|
|
8
|
+
const appRegistry = /* @__PURE__ */ new Map();
|
|
9
|
+
const pendingRegistrations = /* @__PURE__ */ new Map();
|
|
10
|
+
const MAX_REGISTERED_INSTANCES = 1e3;
|
|
11
|
+
function appRegistryKey(instance, redirectURL) {
|
|
12
|
+
return `${instance}::${redirectURL}`;
|
|
13
|
+
}
|
|
14
|
+
function resolveInstanceDomain(input) {
|
|
15
|
+
const withoutProtocol = input.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
|
|
16
|
+
const withoutLeadingAt = withoutProtocol.replace(/^@/, "");
|
|
17
|
+
const domain = withoutLeadingAt.includes("@") ? withoutLeadingAt.split("@").pop() : withoutLeadingAt;
|
|
18
|
+
try {
|
|
19
|
+
return new URL(`https://${domain}`).hostname;
|
|
20
|
+
} catch {
|
|
21
|
+
return domain;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function isPubliclyAddressableInstance(instance) {
|
|
25
|
+
if (!instance || /\s/.test(instance) || instance.endsWith(".")) return false;
|
|
26
|
+
try {
|
|
27
|
+
if (new URL(`https://${instance}`).hostname !== instance) return false;
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (instance === "localhost" || instance.endsWith(".localhost") || instance.endsWith(".local")) return false;
|
|
32
|
+
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(instance)) return false;
|
|
33
|
+
if (instance.includes(":")) return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
async function registerApp(instance, redirectURL, scope, clientName) {
|
|
37
|
+
const app = await $fetch(`https://${instance}/api/v1/apps`, {
|
|
38
|
+
method: "POST",
|
|
39
|
+
body: {
|
|
40
|
+
client_name: clientName,
|
|
41
|
+
redirect_uris: redirectURL,
|
|
42
|
+
scopes: scope
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return { client_id: app.client_id, client_secret: app.client_secret };
|
|
46
|
+
}
|
|
47
|
+
async function getOrRegisterApp(instance, redirectURL, scope, clientName) {
|
|
48
|
+
const key = appRegistryKey(instance, redirectURL);
|
|
49
|
+
const cached = appRegistry.get(key);
|
|
50
|
+
if (cached) return cached;
|
|
51
|
+
const pending = pendingRegistrations.get(key);
|
|
52
|
+
if (pending) return pending;
|
|
53
|
+
const registration = registerApp(instance, redirectURL, scope, clientName).then((app) => {
|
|
54
|
+
if (appRegistry.size >= MAX_REGISTERED_INSTANCES && !appRegistry.has(key)) {
|
|
55
|
+
const oldestKey = appRegistry.keys().next().value;
|
|
56
|
+
if (oldestKey) appRegistry.delete(oldestKey);
|
|
57
|
+
}
|
|
58
|
+
appRegistry.set(key, app);
|
|
59
|
+
return app;
|
|
60
|
+
}).finally(() => {
|
|
61
|
+
pendingRegistrations.delete(key);
|
|
62
|
+
});
|
|
63
|
+
pendingRegistrations.set(key, registration);
|
|
64
|
+
return registration;
|
|
65
|
+
}
|
|
66
|
+
export function defineOAuthMastodonEventHandler({ config: userConfig, onSuccess, onError }) {
|
|
67
|
+
return eventHandler(async (event) => {
|
|
68
|
+
const config = defu({}, userConfig, useRuntimeConfig(event).oauth?.mastodon, {
|
|
69
|
+
clientName: "Nuxt Auth Utils"
|
|
70
|
+
});
|
|
71
|
+
config.scope ||= ["read"];
|
|
72
|
+
const query = getQuery(event);
|
|
73
|
+
if (query.error) {
|
|
74
|
+
const error = createError({
|
|
75
|
+
statusCode: 401,
|
|
76
|
+
message: `Mastodon login failed: ${query.error || "Unknown error"}`,
|
|
77
|
+
data: query
|
|
78
|
+
});
|
|
79
|
+
if (!onError) throw error;
|
|
80
|
+
return onError(event, error);
|
|
81
|
+
}
|
|
82
|
+
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
83
|
+
const state = await handleState(event);
|
|
84
|
+
const scope = (config.scope || ["read"]).join(" ");
|
|
85
|
+
if (!query.code) {
|
|
86
|
+
const rawInstance = query.instance?.toString() || config.instance;
|
|
87
|
+
if (!rawInstance) {
|
|
88
|
+
const error = createError({
|
|
89
|
+
statusCode: 400,
|
|
90
|
+
message: "Mastodon login failed: missing instance. Provide it via the `instance` query parameter (e.g. `/auth/mastodon?instance=mastodon.social`), a full handle (`@user@mastodon.social`), or the `instance` config/`NUXT_OAUTH_MASTODON_INSTANCE` env variable."
|
|
91
|
+
});
|
|
92
|
+
if (!onError) throw error;
|
|
93
|
+
return onError(event, error);
|
|
94
|
+
}
|
|
95
|
+
const instance2 = resolveInstanceDomain(rawInstance);
|
|
96
|
+
if (!isPubliclyAddressableInstance(instance2)) {
|
|
97
|
+
const error = createError({
|
|
98
|
+
statusCode: 400,
|
|
99
|
+
message: `Mastodon login failed: "${instance2}" is not a valid instance domain.`
|
|
100
|
+
});
|
|
101
|
+
if (!onError) throw error;
|
|
102
|
+
return onError(event, error);
|
|
103
|
+
}
|
|
104
|
+
let app;
|
|
105
|
+
try {
|
|
106
|
+
app = await getOrRegisterApp(instance2, redirectURL, scope, config.clientName || "Nuxt Auth Utils");
|
|
107
|
+
} catch {
|
|
108
|
+
const error = createError({
|
|
109
|
+
statusCode: 500,
|
|
110
|
+
message: `Mastodon login failed: could not register the application with instance "${instance2}". Make sure it is a reachable Mastodon (or compatible) server.`
|
|
111
|
+
});
|
|
112
|
+
if (!onError) throw error;
|
|
113
|
+
return onError(event, error);
|
|
114
|
+
}
|
|
115
|
+
const flowState2 = { instance: instance2, clientId: app.client_id, clientSecret: app.client_secret };
|
|
116
|
+
setCookie(event, FLOW_COOKIE_NAME, btoa(JSON.stringify(flowState2)), {
|
|
117
|
+
httpOnly: true,
|
|
118
|
+
secure: !isDevelopment,
|
|
119
|
+
sameSite: "lax",
|
|
120
|
+
maxAge: 60 * 10,
|
|
121
|
+
path: "/"
|
|
122
|
+
});
|
|
123
|
+
return sendRedirect(event, withQuery(`https://${instance2}/oauth/authorize`, {
|
|
124
|
+
client_id: app.client_id,
|
|
125
|
+
redirect_uri: redirectURL,
|
|
126
|
+
response_type: "code",
|
|
127
|
+
scope,
|
|
128
|
+
state
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
if (!state || query.state !== state) {
|
|
132
|
+
return handleInvalidState(event, "mastodon", onError);
|
|
133
|
+
}
|
|
134
|
+
const flowCookie = getCookie(event, FLOW_COOKIE_NAME);
|
|
135
|
+
deleteCookie(event, FLOW_COOKIE_NAME, { path: "/" });
|
|
136
|
+
let flowState;
|
|
137
|
+
try {
|
|
138
|
+
flowState = flowCookie ? JSON.parse(atob(flowCookie)) : void 0;
|
|
139
|
+
} catch {
|
|
140
|
+
flowState = void 0;
|
|
141
|
+
}
|
|
142
|
+
if (!flowState || !isPubliclyAddressableInstance(flowState.instance)) {
|
|
143
|
+
const error = createError({
|
|
144
|
+
statusCode: 400,
|
|
145
|
+
message: "Mastodon login failed: could not recover the application credentials for this login (missing or invalid flow cookie, the flow may have taken too long or cookies are blocked)."
|
|
146
|
+
});
|
|
147
|
+
if (!onError) throw error;
|
|
148
|
+
return onError(event, error);
|
|
149
|
+
}
|
|
150
|
+
const { instance, clientId, clientSecret } = flowState;
|
|
151
|
+
const tokens = await requestAccessToken(`https://${instance}/oauth/token`, {
|
|
152
|
+
body: {
|
|
153
|
+
grant_type: "authorization_code",
|
|
154
|
+
client_id: clientId,
|
|
155
|
+
client_secret: clientSecret,
|
|
156
|
+
redirect_uri: redirectURL,
|
|
157
|
+
code: query.code,
|
|
158
|
+
scope
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
if (tokens.error) {
|
|
162
|
+
return handleAccessTokenErrorResponse(event, "mastodon", tokens, onError);
|
|
163
|
+
}
|
|
164
|
+
const account = await $fetch(`https://${instance}/api/v1/accounts/verify_credentials`, {
|
|
165
|
+
headers: {
|
|
166
|
+
Authorization: `Bearer ${tokens.access_token}`
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const user = {
|
|
170
|
+
...account,
|
|
171
|
+
acct: account.acct.includes("@") ? account.acct : `${account.acct}@${instance}`
|
|
172
|
+
};
|
|
173
|
+
return onSuccess(event, {
|
|
174
|
+
user,
|
|
175
|
+
tokens
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
@@ -51,4 +51,4 @@ export interface OAuthMicrosoftConfig {
|
|
|
51
51
|
*/
|
|
52
52
|
redirectURL?: string;
|
|
53
53
|
}
|
|
54
|
-
export declare function defineOAuthMicrosoftEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthMicrosoftConfig>): any
|
|
54
|
+
export declare function defineOAuthMicrosoftEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthMicrosoftConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -211,5 +211,5 @@ interface OIDCConfiguration {
|
|
|
211
211
|
export declare function defineOAuthOidcEventHandler<TUser = OidcUser>({ config, onSuccess, onError }: OAuthConfig<OAuthOidcConfig, {
|
|
212
212
|
user: TUser;
|
|
213
213
|
tokens: OidcTokens;
|
|
214
|
-
}>): any
|
|
214
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
215
215
|
export {};
|
|
@@ -5,9 +5,7 @@ import { withQuery } from "ufo";
|
|
|
5
5
|
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleInvalidState, handleMissingConfiguration, handlePkceVerifier, handleState, requestAccessToken, handleNonce, parseJwt } from "../utils.js";
|
|
6
6
|
export function defineOAuthOidcEventHandler({ config, onSuccess, onError }) {
|
|
7
7
|
return eventHandler(async (event) => {
|
|
8
|
-
config = defu(config, useRuntimeConfig(event).oauth.oidc
|
|
9
|
-
scope: ["openid"]
|
|
10
|
-
});
|
|
8
|
+
config = defu(config, useRuntimeConfig(event).oauth.oidc);
|
|
11
9
|
const query = getQuery(event);
|
|
12
10
|
if (query.error) {
|
|
13
11
|
const error = createError({
|
|
@@ -28,6 +26,9 @@ export function defineOAuthOidcEventHandler({ config, onSuccess, onError }) {
|
|
|
28
26
|
const nonce = handleNonce(event);
|
|
29
27
|
if (!query.code) {
|
|
30
28
|
config.scope = config.scope || [];
|
|
29
|
+
if (!config.scope.includes("openid")) {
|
|
30
|
+
config.scope.push("openid");
|
|
31
|
+
}
|
|
31
32
|
const authQuery = {
|
|
32
33
|
client_id: config.clientId,
|
|
33
34
|
redirect_uri: redirectURL,
|
|
@@ -85,4 +85,4 @@ export interface OAuthOktaConfig {
|
|
|
85
85
|
*/
|
|
86
86
|
openIdConfigCacheTTL?: number;
|
|
87
87
|
}
|
|
88
|
-
export declare function defineOAuthOktaEventHandler({ config, onSuccess, onError }: OAuthConfigExt<OAuthOktaConfig>): any
|
|
88
|
+
export declare function defineOAuthOktaEventHandler({ config, onSuccess, onError }: OAuthConfigExt<OAuthOktaConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -48,4 +48,4 @@ export interface OAuthOryConfig {
|
|
|
48
48
|
*/
|
|
49
49
|
userURL?: string;
|
|
50
50
|
}
|
|
51
|
-
export declare function defineOAuthOryEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthOryConfig>): any
|
|
51
|
+
export declare function defineOAuthOryEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthOryConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -39,4 +39,4 @@ export interface OAuthOsuConfig {
|
|
|
39
39
|
*/
|
|
40
40
|
redirectURL?: string;
|
|
41
41
|
}
|
|
42
|
-
export declare function defineOAuthOsuEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthOsuConfig>): any
|
|
42
|
+
export declare function defineOAuthOsuEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthOsuConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -49,4 +49,4 @@ export interface OAuthPaypalConfig {
|
|
|
49
49
|
*/
|
|
50
50
|
redirectURL?: string;
|
|
51
51
|
}
|
|
52
|
-
export declare function defineOAuthPaypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): any
|
|
52
|
+
export declare function defineOAuthPaypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -46,4 +46,4 @@ export interface OAuthPolarConfig {
|
|
|
46
46
|
*/
|
|
47
47
|
redirectURL?: string;
|
|
48
48
|
}
|
|
49
|
-
export declare function defineOAuthPolarEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPolarConfig>): any
|
|
49
|
+
export declare function defineOAuthPolarEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPolarConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -70,5 +70,5 @@ interface RiotGamesTokens {
|
|
|
70
70
|
export declare function defineOAuthRiotGamesEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthRiotGamesConfig, {
|
|
71
71
|
user: RiotGamesUser;
|
|
72
72
|
tokens: RiotGamesTokens;
|
|
73
|
-
}>): any
|
|
73
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
74
74
|
export {};
|
|
@@ -123,4 +123,4 @@ export interface OAuthRobloxUser {
|
|
|
123
123
|
visibility: 'SOCIAL_NETWORK_VISIBILITY_UNSPECIFIED' | 'NO_ONE' | 'FRIENDS' | 'FRIENDS_AND_FOLLOWING' | 'FRIENDS_FOLLOWING_AND_FOLLOWERS' | 'EVERYONE';
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
-
export declare function defineOAuthRobloxEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthRobloxConfig>): any
|
|
126
|
+
export declare function defineOAuthRobloxEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthRobloxConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -24,14 +24,19 @@ export interface OAuthSalesforceConfig {
|
|
|
24
24
|
baseURL?: string;
|
|
25
25
|
/**
|
|
26
26
|
* Salesforce OAuth Authorization URL
|
|
27
|
-
* @default '
|
|
27
|
+
* @default '${baseURL}/services/oauth2/authorize'
|
|
28
28
|
*/
|
|
29
29
|
authorizationURL?: string;
|
|
30
30
|
/**
|
|
31
|
-
* Salesforce OAuth
|
|
32
|
-
* @default '
|
|
31
|
+
* Salesforce OAuth Token URL
|
|
32
|
+
* @default '${baseURL}/services/oauth2/token'
|
|
33
33
|
*/
|
|
34
34
|
tokenURL?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Salesforce OAuth User URL
|
|
37
|
+
* @default '${baseURL}/services/oauth2/userinfo'
|
|
38
|
+
*/
|
|
39
|
+
userURL?: string;
|
|
35
40
|
/**
|
|
36
41
|
* Extra authorization parameters to provide to the authorization URL
|
|
37
42
|
* @default {}
|
|
@@ -43,4 +48,4 @@ export interface OAuthSalesforceConfig {
|
|
|
43
48
|
*/
|
|
44
49
|
redirectURL?: string;
|
|
45
50
|
}
|
|
46
|
-
export declare function defineOAuthSalesforceEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthSalesforceConfig>): any
|
|
51
|
+
export declare function defineOAuthSalesforceEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthSalesforceConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -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, handleState, handleInvalidState } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken, handleState, handleInvalidState, handlePkceVerifier } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig, createError } from "#imports";
|
|
6
6
|
export function defineOAuthSalesforceEventHandler({
|
|
7
7
|
config,
|
|
@@ -10,7 +10,7 @@ export function defineOAuthSalesforceEventHandler({
|
|
|
10
10
|
}) {
|
|
11
11
|
return eventHandler(async (event) => {
|
|
12
12
|
const runtimeConfig = useRuntimeConfig(event).oauth?.salesforce;
|
|
13
|
-
const baseURL = config?.baseURL || "https://login.salesforce.com";
|
|
13
|
+
const baseURL = config?.baseURL || runtimeConfig?.baseURL || "https://login.salesforce.com";
|
|
14
14
|
config = defu(config, runtimeConfig, {
|
|
15
15
|
authorizationURL: `${baseURL}/services/oauth2/authorize`,
|
|
16
16
|
tokenURL: `${baseURL}/services/oauth2/token`,
|
|
@@ -30,6 +30,7 @@ export function defineOAuthSalesforceEventHandler({
|
|
|
30
30
|
return handleMissingConfiguration(event, "salesforce", ["clientId", "clientSecret"], onError);
|
|
31
31
|
}
|
|
32
32
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
33
|
+
const pkce = await handlePkceVerifier(event);
|
|
33
34
|
const state = await handleState(event);
|
|
34
35
|
if (!query.code) {
|
|
35
36
|
config.scope = config.scope || ["id"];
|
|
@@ -41,6 +42,8 @@ export function defineOAuthSalesforceEventHandler({
|
|
|
41
42
|
redirect_uri: redirectURL,
|
|
42
43
|
scope: config.scope.join(" "),
|
|
43
44
|
...config.authorizationParams,
|
|
45
|
+
code_challenge: pkce.code_challenge,
|
|
46
|
+
code_challenge_method: pkce.code_challenge_method,
|
|
44
47
|
state
|
|
45
48
|
})
|
|
46
49
|
);
|
|
@@ -54,14 +57,15 @@ export function defineOAuthSalesforceEventHandler({
|
|
|
54
57
|
client_id: config.clientId,
|
|
55
58
|
client_secret: config.clientSecret,
|
|
56
59
|
redirect_uri: redirectURL,
|
|
57
|
-
code: query.code
|
|
60
|
+
code: query.code,
|
|
61
|
+
code_verifier: pkce.code_verifier
|
|
58
62
|
}
|
|
59
63
|
});
|
|
60
64
|
if (tokens.error) {
|
|
61
65
|
return handleAccessTokenErrorResponse(event, "salesforce", tokens, onError);
|
|
62
66
|
}
|
|
63
67
|
const accessToken = tokens.access_token;
|
|
64
|
-
const user = await $fetch(`${baseURL}/services/oauth2/userinfo`, {
|
|
68
|
+
const user = await $fetch(config.userURL || `${baseURL}/services/oauth2/userinfo`, {
|
|
65
69
|
headers: {
|
|
66
70
|
Authorization: `Bearer ${accessToken}`
|
|
67
71
|
}
|
|
@@ -95,4 +95,4 @@ export interface OAuthSeznamUser {
|
|
|
95
95
|
export declare function defineOAuthSeznamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSeznamConfig, {
|
|
96
96
|
user: OAuthSeznamUser;
|
|
97
97
|
tokens: unknown;
|
|
98
|
-
}>): any
|
|
98
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -23,4 +23,4 @@ export interface OAuthShopifyCustomerConfig {
|
|
|
23
23
|
*/
|
|
24
24
|
redirectURL?: string;
|
|
25
25
|
}
|
|
26
|
-
export declare function defineOAuthShopifyCustomerEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthShopifyCustomerConfig>): any
|
|
26
|
+
export declare function defineOAuthShopifyCustomerEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthShopifyCustomerConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -12,7 +12,7 @@ export function defineOAuthShopifyCustomerEventHandler({
|
|
|
12
12
|
config = defu(config, useRuntimeConfig(event).oauth?.shopifyCustomer, {});
|
|
13
13
|
const query = getQuery(event);
|
|
14
14
|
if (!config.clientId || !config.shopDomain) {
|
|
15
|
-
return handleMissingConfiguration(event, "
|
|
15
|
+
return handleMissingConfiguration(event, "shopifyCustomer", ["clientId", "shopDomain"], onError);
|
|
16
16
|
}
|
|
17
17
|
const verifier = await handlePkceVerifier(event);
|
|
18
18
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
@@ -38,4 +38,4 @@ export interface OAuthSlackConfig {
|
|
|
38
38
|
*/
|
|
39
39
|
redirectURL?: string;
|
|
40
40
|
}
|
|
41
|
-
export declare function defineOAuthSlackEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthSlackConfig>): any
|
|
41
|
+
export declare function defineOAuthSlackEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthSlackConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -44,4 +44,4 @@ export interface OAuthSpotifyConfig {
|
|
|
44
44
|
*/
|
|
45
45
|
redirectURL?: string;
|
|
46
46
|
}
|
|
47
|
-
export declare function defineOAuthSpotifyEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSpotifyConfig>): any
|
|
47
|
+
export declare function defineOAuthSpotifyEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSpotifyConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -17,4 +17,4 @@ export interface OAuthSteamConfig {
|
|
|
17
17
|
*/
|
|
18
18
|
redirectURL?: string;
|
|
19
19
|
}
|
|
20
|
-
export declare function defineOAuthSteamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSteamConfig>): any
|
|
20
|
+
export declare function defineOAuthSteamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSteamConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -116,4 +116,4 @@ export interface OAuthStravaTokens {
|
|
|
116
116
|
export declare function defineOAuthStravaEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthStravaConfig, {
|
|
117
117
|
user: OAuthStravaUser;
|
|
118
118
|
tokens: OAuthStravaTokens;
|
|
119
|
-
}>): any
|
|
119
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -42,4 +42,4 @@ export interface OAuthTikTokConfig {
|
|
|
42
42
|
*/
|
|
43
43
|
redirectURL?: string;
|
|
44
44
|
}
|
|
45
|
-
export declare function defineOAuthTikTokEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTikTokConfig>): any
|
|
45
|
+
export declare function defineOAuthTikTokEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTikTokConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -67,5 +67,5 @@ interface TwitchTokens {
|
|
|
67
67
|
export declare function defineOAuthTwitchEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthTwitchConfig, {
|
|
68
68
|
user: TwitchUser;
|
|
69
69
|
tokens: TwitchTokens;
|
|
70
|
-
}>): any
|
|
70
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
71
71
|
export {};
|
|
@@ -43,4 +43,4 @@ export interface OAuthVKConfig {
|
|
|
43
43
|
*/
|
|
44
44
|
redirectURL?: string;
|
|
45
45
|
}
|
|
46
|
-
export declare function defineOAuthVKEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthVKConfig>): any
|
|
46
|
+
export declare function defineOAuthVKEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthVKConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthWechatConfig {
|
|
3
|
+
/**
|
|
4
|
+
* WeChat App ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_WECHAT_APP_ID
|
|
6
|
+
*/
|
|
7
|
+
appId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* WeChat App Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_WECHAT_APP_SECRET
|
|
11
|
+
*/
|
|
12
|
+
appSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* WeChat OAuth Scope
|
|
15
|
+
* @default ['snsapi_login']
|
|
16
|
+
* @see https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
|
|
17
|
+
*/
|
|
18
|
+
scope?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Authorization URL
|
|
21
|
+
* @default 'https://open.weixin.qq.com/connect/qrconnect'
|
|
22
|
+
*/
|
|
23
|
+
authorizationURL?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Access token URL
|
|
26
|
+
* @default 'https://api.weixin.qq.com/sns/oauth2/access_token'
|
|
27
|
+
*/
|
|
28
|
+
tokenURL?: string;
|
|
29
|
+
/**
|
|
30
|
+
* User profile URL
|
|
31
|
+
* @default 'https://api.weixin.qq.com/sns/userinfo'
|
|
32
|
+
*/
|
|
33
|
+
userURL?: string;
|
|
34
|
+
/**
|
|
35
|
+
* User info language.
|
|
36
|
+
* @default 'zh_CN'
|
|
37
|
+
*/
|
|
38
|
+
lang?: 'zh_CN' | 'zh_TW' | 'en';
|
|
39
|
+
/**
|
|
40
|
+
* Redirect URL to allow overriding when public hostname cannot be inferred.
|
|
41
|
+
* @default process.env.NUXT_OAUTH_WECHAT_REDIRECT_URL or current URL
|
|
42
|
+
*/
|
|
43
|
+
redirectURL?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface WechatOAuthTokens {
|
|
46
|
+
access_token: string;
|
|
47
|
+
expires_in: number;
|
|
48
|
+
refresh_token: string;
|
|
49
|
+
openid: string;
|
|
50
|
+
scope: string;
|
|
51
|
+
unionid?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface WechatOAuthUser {
|
|
54
|
+
openid: string;
|
|
55
|
+
nickname: string;
|
|
56
|
+
sex: 0 | 1 | 2;
|
|
57
|
+
province: string;
|
|
58
|
+
city: string;
|
|
59
|
+
country: string;
|
|
60
|
+
headimgurl: string;
|
|
61
|
+
privilege: string[];
|
|
62
|
+
unionid?: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function defineOAuthWechatEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthWechatConfig, {
|
|
65
|
+
user: WechatOAuthUser;
|
|
66
|
+
tokens: WechatOAuthTokens;
|
|
67
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|