nuxt-auth-utils 0.5.28 → 0.5.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +12 -0
- package/dist/runtime/app/plugins/session.client.js +1 -1
- package/dist/runtime/server/lib/oauth/apple.js +12 -3
- package/dist/runtime/server/lib/oauth/atlassian.js +7 -4
- package/dist/runtime/server/lib/oauth/auth0.js +7 -2
- package/dist/runtime/server/lib/oauth/authentik.js +7 -2
- package/dist/runtime/server/lib/oauth/azureb2c.js +2 -2
- package/dist/runtime/server/lib/oauth/battledotnet.js +7 -5
- package/dist/runtime/server/lib/oauth/box.d.ts +95 -0
- package/dist/runtime/server/lib/oauth/box.js +69 -0
- package/dist/runtime/server/lib/oauth/cognito.js +7 -2
- package/dist/runtime/server/lib/oauth/discord.js +7 -2
- package/dist/runtime/server/lib/oauth/dropbox.js +7 -2
- package/dist/runtime/server/lib/oauth/facebook.js +7 -3
- package/dist/runtime/server/lib/oauth/gitea.js +8 -1
- package/dist/runtime/server/lib/oauth/github.js +2 -2
- package/dist/runtime/server/lib/oauth/gitlab.js +8 -1
- package/dist/runtime/server/lib/oauth/google.js +7 -3
- package/dist/runtime/server/lib/oauth/heroku.js +2 -2
- package/dist/runtime/server/lib/oauth/hubspot.js +8 -1
- package/dist/runtime/server/lib/oauth/instagram.js +7 -2
- package/dist/runtime/server/lib/oauth/keycloak.js +9 -2
- package/dist/runtime/server/lib/oauth/kick.js +6 -3
- package/dist/runtime/server/lib/oauth/line.js +7 -3
- package/dist/runtime/server/lib/oauth/linear.js +7 -2
- package/dist/runtime/server/lib/oauth/linkedin.js +7 -2
- package/dist/runtime/server/lib/oauth/livechat.js +9 -5
- package/dist/runtime/server/lib/oauth/microsoft.js +7 -3
- package/dist/runtime/server/lib/oauth/oidc.js +2 -2
- package/dist/runtime/server/lib/oauth/okta.js +3 -4
- package/dist/runtime/server/lib/oauth/ory.js +2 -2
- package/dist/runtime/server/lib/oauth/osu.js +2 -2
- package/dist/runtime/server/lib/oauth/paypal.js +7 -2
- package/dist/runtime/server/lib/oauth/polar.js +7 -2
- package/dist/runtime/server/lib/oauth/riotgames.d.ts +74 -0
- package/dist/runtime/server/lib/oauth/riotgames.js +83 -0
- package/dist/runtime/server/lib/oauth/roblox.js +7 -2
- package/dist/runtime/server/lib/oauth/salesforce.js +2 -2
- package/dist/runtime/server/lib/oauth/seznam.js +6 -2
- package/dist/runtime/server/lib/oauth/shopifyCustomer.js +4 -1
- package/dist/runtime/server/lib/oauth/slack.js +2 -2
- package/dist/runtime/server/lib/oauth/spotify.js +7 -2
- package/dist/runtime/server/lib/oauth/steam.js +6 -2
- package/dist/runtime/server/lib/oauth/strava.js +8 -1
- package/dist/runtime/server/lib/oauth/tiktok.js +7 -2
- package/dist/runtime/server/lib/oauth/twitch.js +7 -2
- package/dist/runtime/server/lib/oauth/vk.js +7 -1
- package/dist/runtime/server/lib/oauth/workos.js +7 -2
- package/dist/runtime/server/lib/oauth/xsuaa.js +7 -2
- package/dist/runtime/server/lib/oauth/yandex.js +8 -1
- package/dist/runtime/server/lib/oauth/zitadel.js +2 -2
- package/dist/runtime/server/lib/utils.d.ts +5 -1
- package/dist/runtime/server/lib/utils.js +11 -9
- package/dist/runtime/types/oauth-config.d.ts +1 -1
- package/dist/runtime/types/webauthn.d.ts +1 -1
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -219,6 +219,7 @@ It can also be set using environment variables:
|
|
|
219
219
|
- Azure B2C
|
|
220
220
|
- Battle.net
|
|
221
221
|
- Bluesky (AT Protocol)
|
|
222
|
+
- Box.com
|
|
222
223
|
- Discord
|
|
223
224
|
- Dropbox
|
|
224
225
|
- Facebook
|
|
@@ -242,6 +243,7 @@ It can also be set using environment variables:
|
|
|
242
243
|
- osu!
|
|
243
244
|
- PayPal
|
|
244
245
|
- Polar
|
|
246
|
+
- Riot Games
|
|
245
247
|
- Salesforce
|
|
246
248
|
- Seznam
|
|
247
249
|
- Shopify Customer
|
|
@@ -304,7 +306,7 @@ if (await verifyPassword(hashedPassword, 'user_password')) {
|
|
|
304
306
|
It also provides a `passwordNeedsRehash` function to check if a password needs to be rehashed. This is useful when the hash settings are changed, such as as increasing the scrypt cost parameters.
|
|
305
307
|
|
|
306
308
|
```ts
|
|
307
|
-
const needsRehash =
|
|
309
|
+
const needsRehash = passwordNeedsRehash(hashedPassword)
|
|
308
310
|
|
|
309
311
|
if (needsRehash) {
|
|
310
312
|
// Password needs to be rehashed
|
|
@@ -416,7 +418,7 @@ export default defineWebAuthnRegisterEventHandler({
|
|
|
416
418
|
// And verify that the email is the same as the one in session
|
|
417
419
|
const session = await getUserSession(event)
|
|
418
420
|
if (session.user?.email && session.user.email !== userBody.userName) {
|
|
419
|
-
throw createError({ statusCode: 400, message: 'Email not matching
|
|
421
|
+
throw createError({ statusCode: 400, message: 'Email not matching current session' })
|
|
420
422
|
}
|
|
421
423
|
|
|
422
424
|
// If he registers a new account with credentials
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -115,6 +115,12 @@ const module$1 = defineNuxtModule({
|
|
|
115
115
|
redirectURL: "",
|
|
116
116
|
baseURL: ""
|
|
117
117
|
});
|
|
118
|
+
runtimeConfig.oauth.box = defu(runtimeConfig.oauth.box, {
|
|
119
|
+
clientId: "",
|
|
120
|
+
clientSecret: "",
|
|
121
|
+
redirectURL: "",
|
|
122
|
+
scope: []
|
|
123
|
+
});
|
|
118
124
|
runtimeConfig.oauth.github = defu(runtimeConfig.oauth.github, {
|
|
119
125
|
clientId: "",
|
|
120
126
|
clientSecret: "",
|
|
@@ -406,6 +412,12 @@ const module$1 = defineNuxtModule({
|
|
|
406
412
|
redirectURL: "",
|
|
407
413
|
scope: []
|
|
408
414
|
});
|
|
415
|
+
runtimeConfig.oauth.riotgames = defu(runtimeConfig.oauth.riotgames, {
|
|
416
|
+
clientId: "",
|
|
417
|
+
clientSecret: "",
|
|
418
|
+
redirectURL: "",
|
|
419
|
+
scope: []
|
|
420
|
+
});
|
|
409
421
|
}
|
|
410
422
|
});
|
|
411
423
|
|
|
@@ -3,7 +3,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|
|
3
3
|
if (!nuxtApp.payload.serverRendered) {
|
|
4
4
|
await useUserSession().fetch();
|
|
5
5
|
} else if (Boolean(nuxtApp.payload.prerenderedAt) || Boolean(nuxtApp.payload.isCached) || nuxtApp.$config.public.auth.loadStrategy === "client-only") {
|
|
6
|
-
nuxtApp.hook("app:
|
|
6
|
+
nuxtApp.hook("app:suspense:resolve", async () => {
|
|
7
7
|
await useUserSession().fetch();
|
|
8
8
|
});
|
|
9
9
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getRequestHeader, readBody, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken, signJwt, verifyJwt } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken, signJwt, verifyJwt } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export function defineOAuthAppleEventHandler({
|
|
7
7
|
config,
|
|
@@ -19,10 +19,15 @@ export function defineOAuthAppleEventHandler({
|
|
|
19
19
|
}
|
|
20
20
|
const isPost = getRequestHeader(event, "content-type") === "application/x-www-form-urlencoded";
|
|
21
21
|
let code;
|
|
22
|
+
let state;
|
|
22
23
|
let user;
|
|
23
24
|
if (isPost) {
|
|
24
|
-
({ code, user } = await readBody(event));
|
|
25
|
+
({ code, state, user } = await readBody(event));
|
|
25
26
|
}
|
|
27
|
+
const storedState = await handleState(event, {
|
|
28
|
+
isCallback: isPost && Boolean(code),
|
|
29
|
+
sameSite: "none"
|
|
30
|
+
});
|
|
26
31
|
if (!isPost || !code) {
|
|
27
32
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
28
33
|
config.scope = Array.isArray(config.scope) ? config.scope.join(" ") : config.scope || "name email";
|
|
@@ -34,10 +39,14 @@ export function defineOAuthAppleEventHandler({
|
|
|
34
39
|
client_id: config.clientId,
|
|
35
40
|
redirect_uri: redirectURL,
|
|
36
41
|
scope: config.scope,
|
|
37
|
-
...config.authorizationParams
|
|
42
|
+
...config.authorizationParams,
|
|
43
|
+
state: storedState
|
|
38
44
|
})
|
|
39
45
|
);
|
|
40
46
|
}
|
|
47
|
+
if (state !== storedState) {
|
|
48
|
+
return handleInvalidState(event, "apple", onError);
|
|
49
|
+
}
|
|
41
50
|
try {
|
|
42
51
|
const secret = await signJwt(
|
|
43
52
|
{
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import {
|
|
5
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
6
5
|
import { useRuntimeConfig, createError } from "#imports";
|
|
7
6
|
export function defineOAuthAtlassianEventHandler({
|
|
8
7
|
config,
|
|
@@ -28,6 +27,7 @@ export function defineOAuthAtlassianEventHandler({
|
|
|
28
27
|
}
|
|
29
28
|
const query = getQuery(event);
|
|
30
29
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
30
|
+
const state = await handleState(event);
|
|
31
31
|
if (!query.code) {
|
|
32
32
|
return sendRedirect(
|
|
33
33
|
event,
|
|
@@ -36,10 +36,10 @@ export function defineOAuthAtlassianEventHandler({
|
|
|
36
36
|
client_id: config.clientId,
|
|
37
37
|
scope: config.scope?.join(" "),
|
|
38
38
|
redirect_uri: redirectURL,
|
|
39
|
-
state: randomUUID(),
|
|
40
39
|
response_type: "code",
|
|
41
40
|
prompt: "consent",
|
|
42
|
-
...config.authorizationParams
|
|
41
|
+
...config.authorizationParams,
|
|
42
|
+
state
|
|
43
43
|
})
|
|
44
44
|
);
|
|
45
45
|
}
|
|
@@ -52,6 +52,9 @@ export function defineOAuthAtlassianEventHandler({
|
|
|
52
52
|
if (!onError) throw error;
|
|
53
53
|
return onError(event, error);
|
|
54
54
|
}
|
|
55
|
+
if (query.state !== state) {
|
|
56
|
+
return handleInvalidState(event, "atlassian", onError);
|
|
57
|
+
}
|
|
55
58
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
56
59
|
headers: {
|
|
57
60
|
"Content-Type": "application/json"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
|
|
7
7
|
return eventHandler(async (event) => {
|
|
@@ -26,6 +26,7 @@ export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
|
|
|
26
26
|
onError
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
|
+
const state = await handleState(event);
|
|
29
30
|
if (!query.code) {
|
|
30
31
|
config.scope = config.scope || ["openid", "offline_access"];
|
|
31
32
|
if (config.emailRequired && !config.scope.includes("email")) {
|
|
@@ -41,10 +42,14 @@ export function defineOAuthAuth0EventHandler({ config, onSuccess, onError }) {
|
|
|
41
42
|
audience: config.audience || "",
|
|
42
43
|
max_age: config.maxAge || 0,
|
|
43
44
|
connection: config.connection || "",
|
|
44
|
-
...config.authorizationParams
|
|
45
|
+
...config.authorizationParams,
|
|
46
|
+
state
|
|
45
47
|
})
|
|
46
48
|
);
|
|
47
49
|
}
|
|
50
|
+
if (query.state !== state) {
|
|
51
|
+
return handleInvalidState(event, "auth0", onError);
|
|
52
|
+
}
|
|
48
53
|
const tokens = await requestAccessToken(tokenURL, {
|
|
49
54
|
headers: {
|
|
50
55
|
"Content-Type": "application/json"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig, createError } from "#imports";
|
|
6
6
|
export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError }) {
|
|
7
7
|
return eventHandler(async (event) => {
|
|
@@ -22,6 +22,7 @@ export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError })
|
|
|
22
22
|
const authorizationURL = `https://${config.domain}/application/o/authorize/`;
|
|
23
23
|
const tokenURL = `https://${config.domain}/application/o/token/`;
|
|
24
24
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
25
|
+
const state = await handleState(event);
|
|
25
26
|
if (!query.code) {
|
|
26
27
|
return sendRedirect(
|
|
27
28
|
event,
|
|
@@ -29,10 +30,14 @@ export function defineOAuthAuthentikEventHandler({ config, onSuccess, onError })
|
|
|
29
30
|
response_type: "code",
|
|
30
31
|
client_id: config.clientId,
|
|
31
32
|
redirect_uri: redirectURL,
|
|
32
|
-
scope: (config.scope || ["openid", "profile", "email"]).join(" ")
|
|
33
|
+
scope: (config.scope || ["openid", "profile", "email"]).join(" "),
|
|
34
|
+
state
|
|
33
35
|
})
|
|
34
36
|
);
|
|
35
37
|
}
|
|
38
|
+
if (query.state !== state) {
|
|
39
|
+
return handleInvalidState(event, "authentik", onError);
|
|
40
|
+
}
|
|
36
41
|
const tokens = await requestAccessToken(tokenURL, {
|
|
37
42
|
headers: {
|
|
38
43
|
"Authorization": `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`,
|
|
@@ -27,10 +27,10 @@ export function defineOAuthAzureB2CEventHandler({ config, onSuccess, onError })
|
|
|
27
27
|
response_type: "code",
|
|
28
28
|
redirect_uri: redirectURL,
|
|
29
29
|
scope: config.scope.join(" "),
|
|
30
|
-
state,
|
|
31
30
|
code_challenge: verifier.code_challenge,
|
|
32
31
|
code_challenge_method: verifier.code_challenge_method,
|
|
33
|
-
...config.authorizationParams
|
|
32
|
+
...config.authorizationParams,
|
|
33
|
+
state
|
|
34
34
|
})
|
|
35
35
|
);
|
|
36
36
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import {
|
|
5
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
6
5
|
import { useRuntimeConfig, createError } from "#imports";
|
|
7
6
|
export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError }) {
|
|
8
7
|
return eventHandler(async (event) => {
|
|
@@ -30,6 +29,7 @@ export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError
|
|
|
30
29
|
);
|
|
31
30
|
}
|
|
32
31
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
32
|
+
const state = await handleState(event);
|
|
33
33
|
if (!query.code) {
|
|
34
34
|
config.scope = config.scope || ["openid"];
|
|
35
35
|
config.region = config.region || "EU";
|
|
@@ -43,13 +43,15 @@ export function defineOAuthBattledotnetEventHandler({ config, onSuccess, onError
|
|
|
43
43
|
client_id: config.clientId,
|
|
44
44
|
redirect_uri: redirectURL,
|
|
45
45
|
scope: config.scope.join(" "),
|
|
46
|
-
state: randomUUID(),
|
|
47
|
-
// Todo: handle PKCE flow
|
|
48
46
|
response_type: "code",
|
|
49
|
-
...config.authorizationParams
|
|
47
|
+
...config.authorizationParams,
|
|
48
|
+
state
|
|
50
49
|
})
|
|
51
50
|
);
|
|
52
51
|
}
|
|
52
|
+
if (query.state !== state) {
|
|
53
|
+
return handleInvalidState(event, "battledotnet", onError);
|
|
54
|
+
}
|
|
53
55
|
config.scope = config.scope || [];
|
|
54
56
|
if (!config.scope.includes("openid")) {
|
|
55
57
|
config.scope.push("openid");
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthBoxConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Box OAuth Client ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_BOX_CLIENT_ID
|
|
6
|
+
*/
|
|
7
|
+
clientId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Box OAuth Client Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_BOX_CLIENT_SECRET
|
|
11
|
+
*/
|
|
12
|
+
clientSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Box OAuth Scope
|
|
15
|
+
* @default []
|
|
16
|
+
* @see https://developer.box.com/guides/api-calls/permissions-and-errors/scopes/
|
|
17
|
+
*/
|
|
18
|
+
scope?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Box OAuth Authorization URL
|
|
21
|
+
* @default 'https://account.box.com/api/oauth2/authorize'
|
|
22
|
+
*/
|
|
23
|
+
authorizationURL?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Box OAuth Token URL
|
|
26
|
+
* @default 'https://api.box.com/oauth2/token'
|
|
27
|
+
*/
|
|
28
|
+
tokenURL?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Box User Info URL
|
|
31
|
+
* @default 'https://api.box.com/2.0/users/me'
|
|
32
|
+
*/
|
|
33
|
+
userURL?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Extra authorization parameters to provide to the authorization URL
|
|
36
|
+
* @see https://developer.box.com/guides/authentication/oauth2/oauth2-setup/
|
|
37
|
+
*/
|
|
38
|
+
authorizationParams?: Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Redirect URL to allow overriding for situations like prod failing to determine public hostname
|
|
41
|
+
* @default process.env.NUXT_OAUTH_BOX_REDIRECT_URL
|
|
42
|
+
*/
|
|
43
|
+
redirectURL?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Box User object returned from /2.0/users/me
|
|
47
|
+
* @see https://developer.box.com/reference/get-users-me/
|
|
48
|
+
* @see https://www.postman.com/boxdev/box-s-public-workspace/example/8119550-f7344611-7834-4040-a4ae-d6b3ef95bfdb
|
|
49
|
+
*/
|
|
50
|
+
interface OAuthBoxUser {
|
|
51
|
+
type: 'user';
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
login: string;
|
|
55
|
+
created_at: string;
|
|
56
|
+
modified_at: string;
|
|
57
|
+
language: string;
|
|
58
|
+
timezone: string;
|
|
59
|
+
space_amount: number;
|
|
60
|
+
space_used: number;
|
|
61
|
+
max_upload_size: number;
|
|
62
|
+
status: 'active' | 'inactive' | 'cannot_delete_edit' | 'cannot_delete_edit_upload';
|
|
63
|
+
job_title?: string;
|
|
64
|
+
phone?: string;
|
|
65
|
+
address?: string;
|
|
66
|
+
avatar_url?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Box OAuth tokens
|
|
70
|
+
* @see https://developer.box.com/reference/post-oauth2-token/
|
|
71
|
+
* @see https://www.postman.com/boxdev/box-s-public-workspace/example/8119550-70a8e5bd-4d25-494c-be2c-5409db9d1ace
|
|
72
|
+
*/
|
|
73
|
+
interface OAuthBoxTokens {
|
|
74
|
+
access_token: string;
|
|
75
|
+
refresh_token: string;
|
|
76
|
+
expires_in: number;
|
|
77
|
+
token_type: 'bearer';
|
|
78
|
+
restricted_to?: Array<{
|
|
79
|
+
scope: string;
|
|
80
|
+
object?: {
|
|
81
|
+
type: string;
|
|
82
|
+
id: string;
|
|
83
|
+
};
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Define an OAuth event handler for Box authentication.
|
|
88
|
+
* @see https://developer.box.com/guides/authentication/oauth2/
|
|
89
|
+
* @see https://www.postman.com/boxdev/box-s-public-workspace/collection/trhp912/box-platform-api
|
|
90
|
+
*/
|
|
91
|
+
export declare function defineOAuthBoxEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthBoxConfig, {
|
|
92
|
+
user: OAuthBoxUser;
|
|
93
|
+
tokens: OAuthBoxTokens;
|
|
94
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { eventHandler, getQuery, sendRedirect, createError } from "h3";
|
|
2
|
+
import { withQuery } from "ufo";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleInvalidState, handleMissingConfiguration, handleState, requestAccessToken } from "../utils.js";
|
|
5
|
+
import { useRuntimeConfig } from "#imports";
|
|
6
|
+
export function defineOAuthBoxEventHandler({ config, onSuccess, onError }) {
|
|
7
|
+
return eventHandler(async (event) => {
|
|
8
|
+
config = defu(config, useRuntimeConfig(event).oauth?.box, {
|
|
9
|
+
authorizationURL: "https://account.box.com/api/oauth2/authorize",
|
|
10
|
+
tokenURL: "https://api.box.com/oauth2/token",
|
|
11
|
+
userURL: "https://api.box.com/2.0/users/me",
|
|
12
|
+
authorizationParams: {}
|
|
13
|
+
});
|
|
14
|
+
const query = getQuery(event);
|
|
15
|
+
if (query.error) {
|
|
16
|
+
const errorMessageParts = [query.error, query.error_description].filter(Boolean).join(": ");
|
|
17
|
+
const error = createError({
|
|
18
|
+
statusCode: 401,
|
|
19
|
+
message: `Box login failed: ${errorMessageParts || "Unknown error"}`,
|
|
20
|
+
data: query
|
|
21
|
+
});
|
|
22
|
+
if (!onError) throw error;
|
|
23
|
+
return onError(event, error);
|
|
24
|
+
}
|
|
25
|
+
if (!config.clientId || !config.clientSecret) {
|
|
26
|
+
return handleMissingConfiguration(event, "box", ["clientId", "clientSecret"], onError);
|
|
27
|
+
}
|
|
28
|
+
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
29
|
+
const state = await handleState(event);
|
|
30
|
+
if (!query.code) {
|
|
31
|
+
const scope = config.scope || [];
|
|
32
|
+
return sendRedirect(
|
|
33
|
+
event,
|
|
34
|
+
withQuery(config.authorizationURL, {
|
|
35
|
+
response_type: "code",
|
|
36
|
+
client_id: config.clientId,
|
|
37
|
+
redirect_uri: redirectURL,
|
|
38
|
+
scope: scope.join(" "),
|
|
39
|
+
...config.authorizationParams,
|
|
40
|
+
state
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (query.state !== state) {
|
|
45
|
+
return handleInvalidState(event, "box", onError);
|
|
46
|
+
}
|
|
47
|
+
const tokens = await requestAccessToken(config.tokenURL, {
|
|
48
|
+
body: {
|
|
49
|
+
grant_type: "authorization_code",
|
|
50
|
+
client_id: config.clientId,
|
|
51
|
+
client_secret: config.clientSecret,
|
|
52
|
+
redirect_uri: redirectURL,
|
|
53
|
+
code: query.code
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
if (tokens.error) {
|
|
57
|
+
return handleAccessTokenErrorResponse(event, "box", tokens, onError);
|
|
58
|
+
}
|
|
59
|
+
const user = await $fetch(config.userURL, {
|
|
60
|
+
headers: {
|
|
61
|
+
Authorization: `Bearer ${tokens.access_token}`
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return onSuccess(event, {
|
|
65
|
+
user,
|
|
66
|
+
tokens
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -2,7 +2,7 @@ import { defu } from "defu";
|
|
|
2
2
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
3
3
|
import { discovery } from "openid-client";
|
|
4
4
|
import { withQuery } from "ufo";
|
|
5
|
-
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleMissingConfiguration, requestAccessToken } from "../utils.js";
|
|
5
|
+
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleInvalidState, handleMissingConfiguration, handleState, requestAccessToken } from "../utils.js";
|
|
6
6
|
import { useRuntimeConfig } from "#imports";
|
|
7
7
|
export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
|
|
8
8
|
return eventHandler(async (event) => {
|
|
@@ -24,6 +24,7 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
|
|
|
24
24
|
} = issuer.serverMetadata();
|
|
25
25
|
const query = getQuery(event);
|
|
26
26
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
27
|
+
const state = await handleState(event);
|
|
27
28
|
if (!query.code) {
|
|
28
29
|
config.scope = config.scope || ["openid", "profile"];
|
|
29
30
|
return sendRedirect(
|
|
@@ -33,10 +34,14 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
|
|
|
33
34
|
redirect_uri: redirectURL,
|
|
34
35
|
response_type: "code",
|
|
35
36
|
scope: config.scope.join(" "),
|
|
36
|
-
...config.authorizationParams
|
|
37
|
+
...config.authorizationParams,
|
|
38
|
+
state
|
|
37
39
|
})
|
|
38
40
|
);
|
|
39
41
|
}
|
|
42
|
+
if (query.state !== state) {
|
|
43
|
+
return handleInvalidState(event, "cognito", onError);
|
|
44
|
+
}
|
|
40
45
|
const tokens = await requestAccessToken(
|
|
41
46
|
tokenURL,
|
|
42
47
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
|
|
7
7
|
return eventHandler(async (event) => {
|
|
@@ -19,6 +19,7 @@ export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
|
|
|
19
19
|
return handleAccessTokenErrorResponse(event, "discord", query, onError);
|
|
20
20
|
}
|
|
21
21
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
22
|
+
const state = await handleState(event);
|
|
22
23
|
if (!query.code) {
|
|
23
24
|
config.scope = config.scope || [];
|
|
24
25
|
if (config.emailRequired && !config.scope.includes("email")) {
|
|
@@ -34,10 +35,14 @@ export function defineOAuthDiscordEventHandler({ config, onSuccess, onError }) {
|
|
|
34
35
|
client_id: config.clientId,
|
|
35
36
|
redirect_uri: redirectURL,
|
|
36
37
|
scope: config.scope.join(" "),
|
|
37
|
-
...config.authorizationParams
|
|
38
|
+
...config.authorizationParams,
|
|
39
|
+
state
|
|
38
40
|
})
|
|
39
41
|
);
|
|
40
42
|
}
|
|
43
|
+
if (query.state !== state) {
|
|
44
|
+
return handleInvalidState(event, "discord", onError);
|
|
45
|
+
}
|
|
41
46
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
42
47
|
body: {
|
|
43
48
|
client_id: config.clientId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig, createError } from "#imports";
|
|
6
6
|
export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
|
|
7
7
|
return eventHandler(async (event) => {
|
|
@@ -15,6 +15,7 @@ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
|
|
|
15
15
|
return handleMissingConfiguration(event, "dropbox", ["clientId", "clientSecret"], onError);
|
|
16
16
|
}
|
|
17
17
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
18
|
+
const state = await handleState(event);
|
|
18
19
|
if (!query.code) {
|
|
19
20
|
config.scope = config.scope || [];
|
|
20
21
|
if (!config.scope.includes("openid")) {
|
|
@@ -30,10 +31,14 @@ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
|
|
|
30
31
|
client_id: config.clientId,
|
|
31
32
|
redirect_uri: redirectURL,
|
|
32
33
|
scope: config.scope.join(" "),
|
|
33
|
-
...config.authorizationParams
|
|
34
|
+
...config.authorizationParams,
|
|
35
|
+
state
|
|
34
36
|
})
|
|
35
37
|
);
|
|
36
38
|
}
|
|
39
|
+
if (query.state !== state) {
|
|
40
|
+
return handleInvalidState(event, "dropbox", onError);
|
|
41
|
+
}
|
|
37
42
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
38
43
|
headers: {
|
|
39
44
|
Authorization: `Basic ${Buffer.from(`${config.clientId}:${config.clientSecret}`).toString("base64")}`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eventHandler, getQuery, sendRedirect, createError } from "h3";
|
|
2
2
|
import { withQuery } from "ufo";
|
|
3
3
|
import { defu } from "defu";
|
|
4
|
-
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
|
|
4
|
+
import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, handleInvalidState, handleState, requestAccessToken } from "../utils.js";
|
|
5
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export function defineOAuthFacebookEventHandler({
|
|
7
7
|
config,
|
|
@@ -28,6 +28,7 @@ export function defineOAuthFacebookEventHandler({
|
|
|
28
28
|
return handleMissingConfiguration(event, "facebook", ["clientId", "clientSecret"], onError);
|
|
29
29
|
}
|
|
30
30
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
31
|
+
const state = await handleState(event);
|
|
31
32
|
if (!query.code) {
|
|
32
33
|
config.scope = [...new Set(config.scope)];
|
|
33
34
|
return sendRedirect(
|
|
@@ -36,11 +37,14 @@ export function defineOAuthFacebookEventHandler({
|
|
|
36
37
|
client_id: config.clientId,
|
|
37
38
|
redirect_uri: redirectURL,
|
|
38
39
|
scope: config.scope.join(" "),
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
...config.authorizationParams,
|
|
41
|
+
state
|
|
41
42
|
})
|
|
42
43
|
);
|
|
43
44
|
}
|
|
45
|
+
if (query.state !== state) {
|
|
46
|
+
return handleInvalidState(event, "facebook", onError);
|
|
47
|
+
}
|
|
44
48
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
45
49
|
body: {
|
|
46
50
|
client_id: config.clientId,
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
handleMissingConfiguration,
|
|
6
6
|
handleAccessTokenErrorResponse,
|
|
7
7
|
getOAuthRedirectURL,
|
|
8
|
+
handleInvalidState,
|
|
9
|
+
handleState,
|
|
8
10
|
requestAccessToken
|
|
9
11
|
} from "../utils.js";
|
|
10
12
|
import { useRuntimeConfig, createError } from "#imports";
|
|
@@ -40,6 +42,7 @@ export function defineOAuthGiteaEventHandler({
|
|
|
40
42
|
);
|
|
41
43
|
}
|
|
42
44
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
45
|
+
const state = await handleState(event);
|
|
43
46
|
if (!query.code) {
|
|
44
47
|
config.scope = config.scope || [];
|
|
45
48
|
if (!config.scope.length) {
|
|
@@ -55,10 +58,14 @@ export function defineOAuthGiteaEventHandler({
|
|
|
55
58
|
client_id: config.clientId,
|
|
56
59
|
redirect_uri: redirectURL,
|
|
57
60
|
scope: config.scope.join(" "),
|
|
58
|
-
...config.authorizationParams
|
|
61
|
+
...config.authorizationParams,
|
|
62
|
+
state
|
|
59
63
|
})
|
|
60
64
|
);
|
|
61
65
|
}
|
|
66
|
+
if (query.state !== state) {
|
|
67
|
+
return handleInvalidState(event, "gitea", onError);
|
|
68
|
+
}
|
|
62
69
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
63
70
|
body: {
|
|
64
71
|
grant_type: "authorization_code",
|
|
@@ -37,8 +37,8 @@ export function defineOAuthGitHubEventHandler({ config, onSuccess, onError }) {
|
|
|
37
37
|
client_id: config.clientId,
|
|
38
38
|
redirect_uri: redirectURL,
|
|
39
39
|
scope: config.scope.join(" "),
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
...config.authorizationParams,
|
|
41
|
+
state
|
|
42
42
|
})
|
|
43
43
|
);
|
|
44
44
|
}
|
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
handleMissingConfiguration,
|
|
6
6
|
handleAccessTokenErrorResponse,
|
|
7
7
|
getOAuthRedirectURL,
|
|
8
|
+
handleInvalidState,
|
|
9
|
+
handleState,
|
|
8
10
|
requestAccessToken
|
|
9
11
|
} from "../utils.js";
|
|
10
12
|
import { useRuntimeConfig, createError } from "#imports";
|
|
@@ -40,6 +42,7 @@ export function defineOAuthGitLabEventHandler({
|
|
|
40
42
|
);
|
|
41
43
|
}
|
|
42
44
|
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
45
|
+
const state = await handleState(event);
|
|
43
46
|
if (!query.code) {
|
|
44
47
|
config.scope = config.scope || [];
|
|
45
48
|
if (!config.scope.length) {
|
|
@@ -55,10 +58,14 @@ export function defineOAuthGitLabEventHandler({
|
|
|
55
58
|
client_id: config.clientId,
|
|
56
59
|
redirect_uri: redirectURL,
|
|
57
60
|
scope: config.scope.join(" "),
|
|
58
|
-
...config.authorizationParams
|
|
61
|
+
...config.authorizationParams,
|
|
62
|
+
state
|
|
59
63
|
})
|
|
60
64
|
);
|
|
61
65
|
}
|
|
66
|
+
if (query.state !== state) {
|
|
67
|
+
return handleInvalidState(event, "gitlab", onError);
|
|
68
|
+
}
|
|
62
69
|
const tokens = await requestAccessToken(config.tokenURL, {
|
|
63
70
|
body: {
|
|
64
71
|
grant_type: "authorization_code",
|