nuxt-auth-utils 0.5.28 → 0.5.29

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 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 = await passwordNeedsRehash(hashedPassword)
309
+ const needsRehash = passwordNeedsRehash(hashedPassword)
308
310
 
309
311
  if (needsRehash) {
310
312
  // Password needs to be rehashed
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.5.28",
4
+ "version": "0.5.29",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
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
 
@@ -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
+ state,
40
+ ...config.authorizationParams
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
+ }
@@ -56,6 +56,8 @@ export function defineOAuthKeycloakEventHandler({
56
56
  redirect_uri: redirectURL,
57
57
  code: query.code
58
58
  }
59
+ }).catch((error) => {
60
+ return handleAccessTokenErrorResponse(event, "keycloak", error?.data || error, onError);
59
61
  });
60
62
  if (tokens.error) {
61
63
  return handleAccessTokenErrorResponse(event, "keycloak", tokens, onError);
@@ -0,0 +1,74 @@
1
+ import type { OAuthConfig } from '#auth-utils';
2
+ export interface OAuthRiotGamesConfig {
3
+ /**
4
+ * RiotGames OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_RIOTGAMES_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * RiotGames OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_RIOTGAMES_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * RiotGames OAuth Scope
15
+ * @default []
16
+ * @see https://beta.developer.riotgames.com/sign-on
17
+ * @example ['cpid', 'offline_access']
18
+ */
19
+ scope?: string[];
20
+ /**
21
+ * RiotGames OAuth Authorization URL
22
+ * @default 'https://auth.riotgames.com/authorize'
23
+ */
24
+ authorizationURL?: string;
25
+ /**
26
+ * Riot OAuth Token URL
27
+ * @default 'https://auth.riotgames.com/token'
28
+ */
29
+ tokenURL?: string;
30
+ /**
31
+ * RiotGames API URL
32
+ * @default 'https://auth.riotgames.com'
33
+ */
34
+ apiURL?: string;
35
+ /**
36
+ * Extra authorization parameters to provide to the authorization URL
37
+ */
38
+ authorizationParams?: Record<string, string>;
39
+ /**
40
+ * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
41
+ * @default process.env.NUXT_OAUTH_RIOTGAMES_REDIRECT_URL
42
+ */
43
+ redirectURL?: string;
44
+ /**
45
+ * API routing values for Accounts Endpoint. You can query for any account in any region.
46
+ * @default 'europe'
47
+ */
48
+ region?: 'americas' | 'europe' | 'asia';
49
+ }
50
+ interface RiotGamesUser extends RiotGamesAccount, RiotGamesUserInfo {
51
+ }
52
+ interface RiotGamesAccount {
53
+ puuid: string;
54
+ gameName: string;
55
+ tagLine: string;
56
+ }
57
+ interface RiotGamesUserInfo {
58
+ sub: string;
59
+ cpid?: string;
60
+ jti: string;
61
+ }
62
+ interface RiotGamesTokens {
63
+ access_token: string;
64
+ refresh_token: string;
65
+ id_token: string;
66
+ expires_in: number;
67
+ scope: string;
68
+ token_type: string;
69
+ }
70
+ export declare function defineOAuthRiotGamesEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthRiotGamesConfig, {
71
+ user: RiotGamesUser;
72
+ tokens: RiotGamesTokens;
73
+ }>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
74
+ export {};
@@ -0,0 +1,83 @@
1
+ import { createError, eventHandler, getQuery, sendRedirect } 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 defineOAuthRiotGamesEventHandler({ config, onSuccess, onError }) {
7
+ return eventHandler(async (event) => {
8
+ config = defu(config, useRuntimeConfig(event).oauth?.riotgames, {
9
+ authorizationURL: "https://auth.riotgames.com/authorize",
10
+ tokenURL: "https://auth.riotgames.com/token",
11
+ apiURL: "https://auth.riotgames.com",
12
+ region: "europe"
13
+ });
14
+ const query = getQuery(event);
15
+ if (query.error) {
16
+ const error = createError({
17
+ statusCode: 401,
18
+ message: `RiotGames login failed: ${query.error || "Unknown error"}`,
19
+ data: query
20
+ });
21
+ if (!onError) throw error;
22
+ return onError(event, error);
23
+ }
24
+ if (!config.clientId || !config.clientSecret) {
25
+ return handleMissingConfiguration(event, "riotgames", ["clientId", "clientSecret"], onError);
26
+ }
27
+ const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
28
+ const state = await handleState(event);
29
+ if (!query.code) {
30
+ config.scope = config.scope || [];
31
+ if (!config.scope.includes("openid")) {
32
+ config.scope.push("openid");
33
+ }
34
+ return sendRedirect(
35
+ event,
36
+ withQuery(config.authorizationURL, {
37
+ client_id: config.clientId,
38
+ redirect_uri: redirectURL,
39
+ response_type: "code",
40
+ scope: config.scope.join(" "),
41
+ state,
42
+ ...config.authorizationParams
43
+ })
44
+ );
45
+ }
46
+ if (query.state !== state) {
47
+ return handleInvalidState(event, "riotgames", onError);
48
+ }
49
+ const tokens = await requestAccessToken(config.tokenURL, {
50
+ body: {
51
+ grant_type: "authorization_code",
52
+ client_id: config.clientId,
53
+ client_secret: config.clientSecret,
54
+ redirect_uri: redirectURL,
55
+ code: query.code
56
+ }
57
+ });
58
+ if (tokens.error) {
59
+ return handleAccessTokenErrorResponse(event, "riotgames", tokens, onError);
60
+ }
61
+ const accessToken = tokens.access_token;
62
+ const [account, userInfo] = await Promise.all([
63
+ $fetch(`https://${config.region}.api.riotgames.com/riot/account/v1/accounts/me`, {
64
+ headers: {
65
+ Authorization: `Bearer ${accessToken}`
66
+ }
67
+ }),
68
+ $fetch(`${config.apiURL}/userinfo`, {
69
+ headers: {
70
+ Authorization: `Bearer ${accessToken}`
71
+ }
72
+ })
73
+ ]);
74
+ const user = {
75
+ ...account,
76
+ ...userInfo
77
+ };
78
+ return onSuccess(event, {
79
+ user,
80
+ tokens
81
+ });
82
+ });
83
+ }
@@ -1,6 +1,6 @@
1
1
  import type { H3Event, H3Error } from 'h3';
2
2
  export type ATProtoProvider = 'bluesky';
3
- export type OAuthProvider = ATProtoProvider | 'atlassian' | 'auth0' | 'authentik' | 'azureb2c' | 'battledotnet' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'gitea' | 'github' | 'gitlab' | 'google' | 'hubspot' | 'instagram' | 'kick' | 'keycloak' | 'line' | 'linear' | 'linkedin' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | 'apple' | 'livechat' | 'salesforce' | 'slack' | 'heroku' | 'roblox' | 'okta' | 'ory' | 'shopifyCustomer' | 'oidc' | 'osu' | (string & {});
3
+ export type OAuthProvider = ATProtoProvider | 'atlassian' | 'auth0' | 'authentik' | 'azureb2c' | 'battledotnet' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'gitea' | 'github' | 'gitlab' | 'google' | 'hubspot' | 'instagram' | 'kick' | 'keycloak' | 'line' | 'linear' | 'linkedin' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | 'apple' | 'livechat' | 'salesforce' | 'slack' | 'heroku' | 'roblox' | 'okta' | 'ory' | 'shopifyCustomer' | 'oidc' | 'osu' | 'riotgames' | 'box' | (string & {});
4
4
  export type OnError = (event: H3Event, error: H3Error) => Promise<void> | void;
5
5
  export interface OAuthConfig<TConfig, TResult = {
6
6
  user: any;
@@ -86,7 +86,7 @@ export interface WebAuthnComposable {
86
86
  * @param user.displayName - The display name to register, used for convenience and personalization and should not be relied upon as a secure identifier for authentication processes
87
87
  * @returns true if the registration was successful
88
88
  */
89
- register: <T extends WebAuthnUser>(data: T) => Promise<boolean>;
89
+ register: <T extends WebAuthnUser>(user: T) => Promise<boolean>;
90
90
  /**
91
91
  * Authenticate a credential
92
92
  * @param userName - The user name to authenticate, can be an email address, a username, or any other form of unique ID chosen by the user
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-auth-utils",
3
- "version": "0.5.28",
3
+ "version": "0.5.29",
4
4
  "description": "Add Authentication to Nuxt applications with secured & sealed cookies sessions.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "license": "MIT",
10
10
  "type": "module",
11
- "packageManager": "pnpm@10.28.0",
11
+ "packageManager": "pnpm@10.29.3",
12
12
  "exports": {
13
13
  ".": {
14
14
  "types": "./dist/types.d.mts",
@@ -40,13 +40,13 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@adonisjs/hash": "^9.1.1",
43
- "@nuxt/kit": "^4.2.2",
43
+ "@nuxt/kit": "^4.3.1",
44
44
  "defu": "^6.1.4",
45
45
  "h3": "^1.15.4",
46
46
  "hookable": "^6.0.1",
47
47
  "jose": "^6.1.3",
48
48
  "ofetch": "^1.5.1",
49
- "openid-client": "^6.8.1",
49
+ "openid-client": "^6.8.2",
50
50
  "pathe": "^2.0.3",
51
51
  "scule": "^1.3.0",
52
52
  "uncrypto": "^0.1.3"
@@ -72,20 +72,20 @@
72
72
  }
73
73
  },
74
74
  "devDependencies": {
75
- "@iconify-json/simple-icons": "^1.2.66",
76
- "@nuxt/devtools": "3.1.1",
77
- "@nuxt/eslint-config": "^1.12.1",
75
+ "@iconify-json/simple-icons": "^1.2.71",
76
+ "@nuxt/devtools": "3.2.1",
77
+ "@nuxt/eslint-config": "^1.15.1",
78
78
  "@nuxt/module-builder": "^1.0.2",
79
- "@nuxt/schema": "^4.2.2",
80
- "@nuxt/test-utils": "^3.23.0",
79
+ "@nuxt/schema": "^4.3.1",
80
+ "@nuxt/test-utils": "^4.0.0",
81
81
  "@types/node": "latest",
82
- "@nuxt/ui": "^4.3.0",
82
+ "@nuxt/ui": "^4.4.0",
83
83
  "@simplewebauthn/types": "^12.0.0",
84
84
  "changelogen": "^0.6.2",
85
- "eslint": "^9.39.2",
86
- "nuxt": "^4.2.2",
85
+ "eslint": "^10.0.0",
86
+ "nuxt": "^4.3.1",
87
87
  "typescript": "5.9.3",
88
- "vitest": "^4.0.17",
89
- "vue-tsc": "^3.2.2"
88
+ "vitest": "^4.0.18",
89
+ "vue-tsc": "^3.2.4"
90
90
  }
91
91
  }