nuxt-auth-utils 0.0.22 → 0.0.24

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
@@ -59,7 +59,7 @@ const { loggedIn, user, session, clear } = useUserSession()
59
59
  </div>
60
60
  <div v-else>
61
61
  <h1>Not logged in</h1>
62
- <a href="/api/auth/github">Login with GitHub</a>
62
+ <a href="/auth/github">Login with GitHub</a>
63
63
  </div>
64
64
  </template>
65
65
  ```
@@ -146,6 +146,7 @@ It can also be set using environment variables:
146
146
  - AWS Cognito
147
147
  - Battle.net
148
148
  - Discord
149
+ - Facebook
149
150
  - GitHub
150
151
  - Google
151
152
  - Keycloak
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.0.22"
4
+ "version": "0.0.24"
5
5
  }
package/dist/module.mjs CHANGED
@@ -1,8 +1,8 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
1
2
  import { defineNuxtModule, createResolver, addImportsDir, addPlugin, addServerHandler } from '@nuxt/kit';
2
3
  import { join } from 'pathe';
3
4
  import { defu } from 'defu';
4
5
  import { randomUUID } from 'uncrypto';
5
- import { readFile, writeFile } from 'node:fs/promises';
6
6
 
7
7
  const module = defineNuxtModule({
8
8
  meta: {
@@ -119,6 +119,10 @@ const module = defineNuxtModule({
119
119
  region: "",
120
120
  userPoolId: ""
121
121
  });
122
+ runtimeConfig.oauth.facebook = defu(runtimeConfig.oauth.facebook, {
123
+ clientId: "",
124
+ clientSecret: ""
125
+ });
122
126
  }
123
127
  });
124
128
 
@@ -14,7 +14,8 @@ async function fetch() {
14
14
  useSessionState().value = await useRequestFetch()("/api/_auth/session", {
15
15
  headers: {
16
16
  Accept: "text/json"
17
- }
17
+ },
18
+ retry: false
18
19
  }).catch(() => ({}));
19
20
  }
20
21
  async function clear() {
@@ -1,9 +1,9 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
3
  import { ofetch } from "ofetch";
3
4
  import { withQuery, parsePath } from "ufo";
4
5
  import { defu } from "defu";
5
6
  import { useRuntimeConfig } from "#imports";
6
- import { randomUUID } from "crypto";
7
7
  export function battledotnetEventHandler({ config, onSuccess, onError }) {
8
8
  return eventHandler(async (event) => {
9
9
  config = defu(config, useRuntimeConfig(event).oauth?.battledotnet, {
@@ -65,7 +65,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }) {
65
65
  method: "POST",
66
66
  headers: {
67
67
  "Content-Type": "application/x-www-form-urlencoded",
68
- Authorization: `Basic ${authCode}`
68
+ "Authorization": `Basic ${authCode}`
69
69
  },
70
70
  params: {
71
71
  code,
@@ -91,7 +91,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }) {
91
91
  const user = await ofetch("https://oauth.battle.net/userinfo", {
92
92
  headers: {
93
93
  "User-Agent": `Battledotnet-OAuth-${config.clientId}`,
94
- Authorization: `Bearer ${accessToken}`
94
+ "Authorization": `Bearer ${accessToken}`
95
95
  }
96
96
  });
97
97
  if (!user) {
@@ -75,7 +75,7 @@ export function discordEventHandler({ config, onSuccess, onError }) {
75
75
  const user = await ofetch("https://discord.com/api/users/@me", {
76
76
  headers: {
77
77
  "user-agent": "Nuxt Auth Utils",
78
- Authorization: `Bearer ${accessToken}`
78
+ "Authorization": `Bearer ${accessToken}`
79
79
  }
80
80
  });
81
81
  return onSuccess(event, {
@@ -0,0 +1,36 @@
1
+ import type { OAuthConfig } from '#auth-utils';
2
+ export interface OAuthFacebookConfig {
3
+ /**
4
+ * Facebook OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_FACEBOOK_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * Facebook OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_FACEBOOK_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * Facebook OAuth Scope
15
+ * @default []
16
+ * @see https://developers.facebook.com/docs/permissions
17
+ * @example [ 'email' ],
18
+ */
19
+ scope?: string[];
20
+ /**
21
+ * Facebook OAuth Authorization URL
22
+ * @default 'https://www.facebook.com/v19.0/dialog/oauth'
23
+ */
24
+ authorizationURL?: string;
25
+ /**
26
+ * Facebook OAuth Token URL
27
+ * @default 'https://graph.facebook.com/v19.0/oauth/access_token'
28
+ */
29
+ tokenURL?: string;
30
+ /**
31
+ * Extra authorization parameters to provide to the authorization URL
32
+ * @see https://developers.facebook.com/docs/facebook-login/guides/advanced/manual-flow/
33
+ */
34
+ authorizationParams?: Record<string, string>;
35
+ }
36
+ export declare function facebookEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthFacebookConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
@@ -0,0 +1,86 @@
1
+ import {
2
+ eventHandler,
3
+ createError,
4
+ getQuery,
5
+ getRequestURL,
6
+ sendRedirect
7
+ } from "h3";
8
+ import { ofetch } from "ofetch";
9
+ import { withQuery } from "ufo";
10
+ import { defu } from "defu";
11
+ import { useRuntimeConfig } from "#imports";
12
+ export function facebookEventHandler({
13
+ config,
14
+ onSuccess,
15
+ onError
16
+ }) {
17
+ return eventHandler(async (event) => {
18
+ config = defu(config, useRuntimeConfig(event).oauth?.facebook, {
19
+ authorizationURL: "https://www.facebook.com/v19.0/dialog/oauth",
20
+ tokenURL: "https://graph.facebook.com/v19.0/oauth/access_token",
21
+ authorizationParams: {}
22
+ });
23
+ const query = getQuery(event);
24
+ if (query.error) {
25
+ const error = createError({
26
+ statusCode: 401,
27
+ message: `Facebook login failed: ${query.error || "Unknown error"}`,
28
+ data: query
29
+ });
30
+ if (!onError)
31
+ throw error;
32
+ return onError(event, error);
33
+ }
34
+ if (!config.clientId) {
35
+ const error = createError({
36
+ statusCode: 500,
37
+ message: "Missing NUXT_OAUTH_FACEBOOK_CLIENT_ID or NUXT_OAUTH_FACEBOOK_CLIENT_SECRET env variables."
38
+ });
39
+ if (!onError)
40
+ throw error;
41
+ return onError(event, error);
42
+ }
43
+ const redirectUrl = getRequestURL(event).href;
44
+ if (!query.code) {
45
+ config.scope = config.scope || [];
46
+ return sendRedirect(
47
+ event,
48
+ withQuery(config.authorizationURL, {
49
+ client_id: config.clientId,
50
+ redirect_uri: redirectUrl,
51
+ scope: config.scope.join(" ")
52
+ })
53
+ );
54
+ }
55
+ const tokens = await $fetch(config.tokenURL, {
56
+ method: "POST",
57
+ body: {
58
+ client_id: config.clientId,
59
+ client_secret: config.clientSecret,
60
+ redirect_uri: redirectUrl,
61
+ code: query.code
62
+ }
63
+ });
64
+ if (tokens.error) {
65
+ const error = createError({
66
+ statusCode: 401,
67
+ message: `Facebook login failed: ${tokens.error || "Unknown error"}`,
68
+ data: tokens
69
+ });
70
+ if (!onError)
71
+ throw error;
72
+ return onError(event, error);
73
+ }
74
+ const accessToken = tokens.access_token;
75
+ const user = await ofetch(
76
+ `https://graph.facebook.com/v19.0/me?fields=id,name&access_token=${accessToken}`
77
+ );
78
+ if (!user) {
79
+ throw new Error("Facebook login failed: no user found");
80
+ }
81
+ return onSuccess(event, {
82
+ user,
83
+ tokens
84
+ });
85
+ });
86
+ }
@@ -71,14 +71,14 @@ export function githubEventHandler({ config, onSuccess, onError }) {
71
71
  const user = await ofetch("https://api.github.com/user", {
72
72
  headers: {
73
73
  "User-Agent": `Github-OAuth-${config.clientId}`,
74
- Authorization: `token ${accessToken}`
74
+ "Authorization": `token ${accessToken}`
75
75
  }
76
76
  });
77
77
  if (!user.email && config.emailRequired) {
78
78
  const emails = await ofetch("https://api.github.com/user/emails", {
79
79
  headers: {
80
80
  "User-Agent": `Github-OAuth-${config.clientId}`,
81
- Authorization: `token ${accessToken}`
81
+ "Authorization": `token ${accessToken}`
82
82
  }
83
83
  });
84
84
  const primaryEmail = emails.find((email) => email.primary);
@@ -74,7 +74,7 @@ export function linkedinEventHandler({ config, onSuccess, onError }) {
74
74
  const user = await ofetch("https://api.linkedin.com/v2/userinfo", {
75
75
  headers: {
76
76
  "user-agent": "Nuxt Auth Utils",
77
- Authorization: `Bearer ${accessToken}`
77
+ "Authorization": `Bearer ${accessToken}`
78
78
  }
79
79
  });
80
80
  return onSuccess(event, {
@@ -43,7 +43,7 @@ export function spotifyEventHandler({ config, onSuccess, onError }) {
43
43
  {
44
44
  method: "POST",
45
45
  headers: {
46
- Authorization: `Basic ${authCode}`,
46
+ "Authorization": `Basic ${authCode}`,
47
47
  "Content-Type": "application/x-www-form-urlencoded"
48
48
  },
49
49
  params: {
@@ -6,9 +6,9 @@ export interface OAuthTwitchConfig {
6
6
  */
7
7
  clientId?: string;
8
8
  /**
9
- * Twitch OAuth Client Secret
10
- * @default process.env.NUXT_OAUTH_TWITCH_CLIENT_SECRET
11
- */
9
+ * Twitch OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_TWITCH_CLIENT_SECRET
11
+ */
12
12
  clientSecret?: string;
13
13
  /**
14
14
  * Twitch OAuth Scope
@@ -69,7 +69,7 @@ export function twitchEventHandler({ config, onSuccess, onError }) {
69
69
  const users = await ofetch("https://api.twitch.tv/helix/users", {
70
70
  headers: {
71
71
  "Client-ID": config.clientId,
72
- Authorization: `Bearer ${accessToken}`
72
+ "Authorization": `Bearer ${accessToken}`
73
73
  }
74
74
  });
75
75
  const user = users.data?.[0];
@@ -9,6 +9,7 @@ import { battledotnetEventHandler } from '../lib/oauth/battledotnet';
9
9
  import { keycloakEventHandler } from '../lib/oauth/keycloak';
10
10
  import { linkedinEventHandler } from '../lib/oauth/linkedin';
11
11
  import { cognitoEventHandler } from '../lib/oauth/cognito';
12
+ import { facebookEventHandler } from '../lib/oauth/facebook';
12
13
  export declare const oauth: {
13
14
  githubEventHandler: typeof githubEventHandler;
14
15
  spotifyEventHandler: typeof spotifyEventHandler;
@@ -21,4 +22,5 @@ export declare const oauth: {
21
22
  keycloakEventHandler: typeof keycloakEventHandler;
22
23
  linkedinEventHandler: typeof linkedinEventHandler;
23
24
  cognitoEventHandler: typeof cognitoEventHandler;
25
+ facebookEventHandler: typeof facebookEventHandler;
24
26
  };
@@ -9,6 +9,7 @@ import { battledotnetEventHandler } from "../lib/oauth/battledotnet.mjs";
9
9
  import { keycloakEventHandler } from "../lib/oauth/keycloak.mjs";
10
10
  import { linkedinEventHandler } from "../lib/oauth/linkedin.mjs";
11
11
  import { cognitoEventHandler } from "../lib/oauth/cognito.mjs";
12
+ import { facebookEventHandler } from "../lib/oauth/facebook.mjs";
12
13
  export const oauth = {
13
14
  githubEventHandler,
14
15
  spotifyEventHandler,
@@ -20,5 +21,6 @@ export const oauth = {
20
21
  battledotnetEventHandler,
21
22
  keycloakEventHandler,
22
23
  linkedinEventHandler,
23
- cognitoEventHandler
24
+ cognitoEventHandler,
25
+ facebookEventHandler
24
26
  };
@@ -6,11 +6,11 @@ export interface SessionHooks {
6
6
  * - Add extra properties to the session
7
7
  * - Throw an error if the session could not be verified (with a database for example)
8
8
  */
9
- 'fetch': (session: UserSessionRequired, event: H3Event) => void | Promise<void>;
9
+ fetch: (session: UserSessionRequired, event: H3Event) => void | Promise<void>;
10
10
  /**
11
11
  * Called before clearing the session
12
12
  */
13
- 'clear': (session: UserSession, event: H3Event) => void | Promise<void>;
13
+ clear: (session: UserSession, event: H3Event) => void | Promise<void>;
14
14
  }
15
15
  export declare const sessionHooks: import("hookable").Hookable<SessionHooks, import("hookable").HookKeys<SessionHooks>>;
16
16
  export declare function getUserSession(event: H3Event): Promise<UserSession>;
@@ -27,4 +27,14 @@ export declare function setUserSession(event: H3Event, data: UserSession): Promi
27
27
  */
28
28
  export declare function replaceUserSession(event: H3Event, data: UserSession): Promise<UserSession>;
29
29
  export declare function clearUserSession(event: H3Event): Promise<boolean>;
30
- export declare function requireUserSession(event: H3Event): Promise<UserSessionRequired>;
30
+ /**
31
+ * Require a user session
32
+ * @param event
33
+ * @param opts Options to customize the error message and status code
34
+ * @param opts.statusCode The status code to use for the error (defaults to 401)
35
+ * @param opts.message The message to use for the error (defaults to Unauthorized)
36
+ */
37
+ export declare function requireUserSession(event: H3Event, opts?: {
38
+ statusCode?: number;
39
+ message?: string;
40
+ }): Promise<UserSessionRequired>;
@@ -23,12 +23,12 @@ export async function clearUserSession(event) {
23
23
  await session.clear();
24
24
  return true;
25
25
  }
26
- export async function requireUserSession(event) {
26
+ export async function requireUserSession(event, opts = {}) {
27
27
  const userSession = await getUserSession(event);
28
28
  if (!userSession.user) {
29
29
  throw createError({
30
- statusCode: 401,
31
- message: "Unauthorized"
30
+ statusCode: opts.statusCode || 401,
31
+ message: opts.message || "Unauthorized"
32
32
  });
33
33
  }
34
34
  return userSession;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-auth-utils",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "description": "Minimalist Auth module for Nuxt with SSR",
5
5
  "repository": "Atinux/nuxt-auth-utils",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "test:watch": "vitest watch"
31
31
  },
32
32
  "dependencies": {
33
- "@nuxt/kit": "^3.11.1",
33
+ "@nuxt/kit": "^3.11.2",
34
34
  "defu": "^6.1.4",
35
35
  "hookable": "^5.5.3",
36
36
  "ofetch": "^1.3.4",
@@ -39,20 +39,20 @@
39
39
  "uncrypto": "^0.1.3"
40
40
  },
41
41
  "devDependencies": {
42
- "@iconify-json/simple-icons": "^1.1.96",
42
+ "@iconify-json/simple-icons": "^1.1.99",
43
43
  "@nuxt/devtools": "latest",
44
- "@nuxt/eslint-config": "^0.2.0",
44
+ "@nuxt/eslint-config": "^0.3.8",
45
45
  "@nuxt/module-builder": "^0.5.5",
46
- "@nuxt/schema": "^3.11.1",
47
- "@nuxt/test-utils": "^3.12.0",
48
- "@nuxt/ui": "^2.14.2",
49
- "@nuxt/ui-pro": "^1.0.2",
50
- "@types/node": "^20.11.30",
46
+ "@nuxt/schema": "^3.11.2",
47
+ "@nuxt/test-utils": "^3.12.1",
48
+ "@nuxt/ui": "^2.15.2",
49
+ "@nuxt/ui-pro": "^1.1.0",
50
+ "@types/node": "^20.12.7",
51
51
  "changelogen": "^0.5.5",
52
- "eslint": "^8.57.0",
53
- "nuxt": "^3.11.1",
54
- "typescript": "^5.4.3",
55
- "vitest": "^1.4.0",
56
- "vue-tsc": "^2.0.7"
52
+ "eslint": "^9.0.0",
53
+ "nuxt": "^3.11.2",
54
+ "typescript": "^5.4.5",
55
+ "vitest": "^1.5.0",
56
+ "vue-tsc": "^2.0.13"
57
57
  }
58
58
  }