nuxt-auth-utils 0.0.8 → 0.0.10

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
@@ -150,12 +150,14 @@ It can also be set using environment variables:
150
150
  #### Supported OAuth Providers
151
151
 
152
152
  - Auth0
153
+ - Battle.net
153
154
  - Discord
154
155
  - GitHub
155
156
  - Google
157
+ - LinkedIn
158
+ - Microsoft
156
159
  - Spotify
157
160
  - Twitch
158
- - Battle.net
159
161
 
160
162
  You can add your favorite provider by creating a new file in [src/runtime/server/lib/oauth/](./src/runtime/server/lib/oauth/).
161
163
 
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.0.8"
4
+ "version": "0.0.10"
5
5
  }
package/dist/module.mjs CHANGED
@@ -77,7 +77,17 @@ const module = defineNuxtModule({
77
77
  runtimeConfig.oauth.auth0 = defu(runtimeConfig.oauth.auth0, {
78
78
  clientId: "",
79
79
  clientSecret: "",
80
- domain: ""
80
+ domain: "",
81
+ audience: ""
82
+ });
83
+ runtimeConfig.oauth.microsoft = defu(runtimeConfig.oauth.microsoft, {
84
+ clientId: "",
85
+ clientSecret: "",
86
+ tenant: "",
87
+ scope: [],
88
+ authorizationURL: "",
89
+ tokenURL: "",
90
+ userURL: ""
81
91
  });
82
92
  runtimeConfig.oauth.discord = defu(runtimeConfig.oauth.discord, {
83
93
  clientId: "",
@@ -87,6 +97,10 @@ const module = defineNuxtModule({
87
97
  clientId: "",
88
98
  clientSecret: ""
89
99
  });
100
+ runtimeConfig.oauth.linkedin = defu(runtimeConfig.oauth.linkedin, {
101
+ clientId: "",
102
+ clientSecret: ""
103
+ });
90
104
  }
91
105
  });
92
106
 
@@ -32,5 +32,11 @@ export interface OAuthAuth0Config {
32
32
  * @default false
33
33
  */
34
34
  emailRequired?: boolean;
35
+ /**
36
+ * Maximum Authentication Age. If the elapsed time is greater than this value, the OP must attempt to actively re-authenticate the end-user.
37
+ * @default 0
38
+ * @see https://auth0.com/docs/authenticate/login/max-age-reauthentication
39
+ */
40
+ maxAge?: number;
35
41
  }
36
42
  export declare function auth0EventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthAuth0Config>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
@@ -31,7 +31,8 @@ export function auth0EventHandler({ config, onSuccess, onError }) {
31
31
  client_id: config.clientId,
32
32
  redirect_uri: redirectUrl,
33
33
  scope: config.scope.join(" "),
34
- audience: config.audience || ""
34
+ audience: config.audience || "",
35
+ max_age: config.maxAge || 0
35
36
  })
36
37
  );
37
38
  }
@@ -60,7 +60,6 @@ export function discordEventHandler({ config, onSuccess, onError }) {
60
60
  return { error };
61
61
  });
62
62
  if (tokens.error) {
63
- console.log(tokens);
64
63
  const error = createError({
65
64
  statusCode: 401,
66
65
  message: `Discord login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
@@ -0,0 +1,44 @@
1
+ import type { H3Event, H3Error } from 'h3';
2
+ export interface OAuthLinkedInConfig {
3
+ /**
4
+ * LinkedIn OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_LINKEDIN_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * LinkedIn OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_LINKEDIN_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * LinkedIn OAuth Scope
15
+ * @default ['openid', 'profile', 'email']
16
+ * @example ['openid', 'profile']
17
+ */
18
+ scope?: string[];
19
+ /**
20
+ * Require email from user, adds the ['email'] scope if not present
21
+ * @default false
22
+ */
23
+ emailRequired?: boolean;
24
+ /**
25
+ * LinkedIn OAuth Authorization URL
26
+ * @default 'https://www.linkedin.com/oauth/v2/authorization'
27
+ */
28
+ authorizationURL?: string;
29
+ /**
30
+ * LinkedIn OAuth Token URL
31
+ * @default 'https://www.linkedin.com/oauth/v2/accessToken'
32
+ */
33
+ tokenURL?: string;
34
+ }
35
+ interface OAuthConfig {
36
+ config?: OAuthLinkedInConfig;
37
+ onSuccess: (event: H3Event, result: {
38
+ user: any;
39
+ tokens: any;
40
+ }) => Promise<void> | void;
41
+ onError?: (event: H3Event, error: H3Error) => Promise<void> | void;
42
+ }
43
+ export declare function linkedinEventHandler({ config, onSuccess, onError }: OAuthConfig): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
44
+ export {};
@@ -0,0 +1,83 @@
1
+ import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
+ import { withQuery, parseURL, stringifyParsedURL } from "ufo";
3
+ import { ofetch } from "ofetch";
4
+ import { defu } from "defu";
5
+ import { useRuntimeConfig } from "#imports";
6
+ export function linkedinEventHandler({ config, onSuccess, onError }) {
7
+ return eventHandler(async (event) => {
8
+ config = defu(config, useRuntimeConfig(event).oauth?.linkedin, {
9
+ authorizationURL: "https://www.linkedin.com/oauth/v2/authorization",
10
+ tokenURL: "https://www.linkedin.com/oauth/v2/accessToken"
11
+ });
12
+ const { code } = getQuery(event);
13
+ if (!config.clientId || !config.clientSecret) {
14
+ const error = createError({
15
+ statusCode: 500,
16
+ message: "Missing NUXT_OAUTH_LINKEDIN_CLIENT_ID or NUXT_OAUTH_LINKEDIN_CLIENT_SECRET env variables."
17
+ });
18
+ if (!onError)
19
+ throw error;
20
+ return onError(event, error);
21
+ }
22
+ const redirectUrl = getRequestURL(event).href;
23
+ if (!code) {
24
+ config.scope = config.scope || [];
25
+ if (!config.scope.length) {
26
+ config.scope.push("profile", "openid", "email");
27
+ }
28
+ if (config.emailRequired && !config.scope.includes("email")) {
29
+ config.scope.push("email");
30
+ }
31
+ return sendRedirect(
32
+ event,
33
+ withQuery(config.authorizationURL, {
34
+ response_type: "code",
35
+ client_id: config.clientId,
36
+ redirect_uri: redirectUrl,
37
+ scope: config.scope.join(" ")
38
+ })
39
+ );
40
+ }
41
+ const parsedRedirectUrl = parseURL(redirectUrl);
42
+ parsedRedirectUrl.search = "";
43
+ const tokens = await ofetch(
44
+ config.tokenURL,
45
+ {
46
+ method: "POST",
47
+ headers: {
48
+ "Content-Type": "application/x-www-form-urlencoded"
49
+ },
50
+ body: new URLSearchParams({
51
+ grant_type: "authorization_code",
52
+ code,
53
+ client_id: config.clientId,
54
+ client_secret: config.clientSecret,
55
+ redirect_uri: stringifyParsedURL(parsedRedirectUrl)
56
+ }).toString()
57
+ }
58
+ ).catch((error) => {
59
+ return { error };
60
+ });
61
+ if (tokens.error) {
62
+ const error = createError({
63
+ statusCode: 401,
64
+ message: `LinkedIn login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
65
+ data: tokens
66
+ });
67
+ if (!onError)
68
+ throw error;
69
+ return onError(event, error);
70
+ }
71
+ const accessToken = tokens.access_token;
72
+ const user = await ofetch("https://api.linkedin.com/v2/userinfo", {
73
+ headers: {
74
+ "user-agent": "Nuxt Auth Utils",
75
+ Authorization: `Bearer ${accessToken}`
76
+ }
77
+ });
78
+ return onSuccess(event, {
79
+ tokens,
80
+ user
81
+ });
82
+ });
83
+ }
@@ -0,0 +1,52 @@
1
+ import type { H3Event, H3Error } from 'h3';
2
+ export interface OAuthMicrosoftConfig {
3
+ /**
4
+ * Microsoft OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_MICROSOFT_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * Microsoft OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_MICROSOFT_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * Microsoft OAuth Tenant ID
15
+ * @default process.env.NUXT_OAUTH_MICROSOFT_TENANT
16
+ */
17
+ tenant?: string;
18
+ /**
19
+ * Microsoft OAuth Scope
20
+ * @default ['User.Read']
21
+ * @see https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc
22
+ */
23
+ scope?: string[];
24
+ /**
25
+ * Microsoft OAuth Authorization URL
26
+ * @default https://login.microsoftonline.com/${tenant}/oauth2/v2.0/authorize
27
+ * @see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
28
+ */
29
+ authorizationURL?: string;
30
+ /**
31
+ * Microsoft OAuth Token URL
32
+ * @default https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token
33
+ * @see https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
34
+ */
35
+ tokenURL?: string;
36
+ /**
37
+ * Microsoft OAuth User URL
38
+ * @default https://graph.microsoft.com/v1.0/me
39
+ * @see https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http
40
+ */
41
+ userURL?: string;
42
+ }
43
+ interface OAuthConfig {
44
+ config?: OAuthMicrosoftConfig;
45
+ onSuccess: (event: H3Event, result: {
46
+ user: any;
47
+ tokens: any;
48
+ }) => Promise<void> | void;
49
+ onError?: (event: H3Event, error: H3Error) => Promise<void> | void;
50
+ }
51
+ export declare function microsoftEventHandler({ config, onSuccess, onError }: OAuthConfig): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
52
+ export {};
@@ -0,0 +1,87 @@
1
+ import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
+ import { withQuery, parsePath } from "ufo";
3
+ import { ofetch } from "ofetch";
4
+ import { defu } from "defu";
5
+ import { useRuntimeConfig } from "#imports";
6
+ export function microsoftEventHandler({ config, onSuccess, onError }) {
7
+ return eventHandler(async (event) => {
8
+ config = defu(config, useRuntimeConfig(event).oauth?.microsoft);
9
+ const { code } = getQuery(event);
10
+ if (!config.clientId || !config.clientSecret || !config.tenant) {
11
+ const error = createError({
12
+ statusCode: 500,
13
+ message: "Missing NUXT_OAUTH_MICROSOFT_CLIENT_ID or NUXT_OAUTH_MICROSOFT_CLIENT_SECRET or NUXT_OAUTH_MICROSOFT_TENANT env variables."
14
+ });
15
+ if (!onError)
16
+ throw error;
17
+ return onError(event, error);
18
+ }
19
+ const authorizationURL = config.authorizationURL || `https://login.microsoftonline.com/${config.tenant}/oauth2/v2.0/authorize`;
20
+ const tokenURL = config.tokenURL || `https://login.microsoftonline.com/${config.tenant}/oauth2/v2.0/token`;
21
+ const redirectUrl = getRequestURL(event).href;
22
+ if (!code) {
23
+ const scope = config.scope && config.scope.length > 0 ? config.scope : ["User.Read"];
24
+ return sendRedirect(
25
+ event,
26
+ withQuery(authorizationURL, {
27
+ client_id: config.clientId,
28
+ response_type: "code",
29
+ redirect_uri: redirectUrl,
30
+ scope: scope.join("%20")
31
+ })
32
+ );
33
+ }
34
+ const data = new URLSearchParams();
35
+ data.append("grant_type", "authorization_code");
36
+ data.append("client_id", config.clientId);
37
+ data.append("client_secret", config.clientSecret);
38
+ data.append("redirect_uri", parsePath(redirectUrl).pathname);
39
+ data.append("code", String(code));
40
+ const tokens = await ofetch(
41
+ tokenURL,
42
+ {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/x-www-form-urlencoded"
46
+ },
47
+ body: data
48
+ }
49
+ ).catch((error) => {
50
+ return { error };
51
+ });
52
+ if (tokens.error) {
53
+ const error = createError({
54
+ statusCode: 401,
55
+ message: `Microsoft login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
56
+ data: tokens
57
+ });
58
+ if (!onError)
59
+ throw error;
60
+ return onError(event, error);
61
+ }
62
+ const tokenType = tokens.token_type;
63
+ const accessToken = tokens.access_token;
64
+ const userURL = config.userURL || "https://graph.microsoft.com/v1.0/me";
65
+ const user = await ofetch(userURL, {
66
+ headers: {
67
+ Authorization: `${tokenType} ${accessToken}`
68
+ }
69
+ }).catch((error) => {
70
+ return { error };
71
+ });
72
+ if (user.error) {
73
+ const error = createError({
74
+ statusCode: 401,
75
+ message: `Microsoft login failed: ${user.error || "Unknown error"}`,
76
+ data: user
77
+ });
78
+ if (!onError)
79
+ throw error;
80
+ return onError(event, error);
81
+ }
82
+ return onSuccess(event, {
83
+ tokens,
84
+ user
85
+ });
86
+ });
87
+ }
@@ -3,14 +3,18 @@ import { googleEventHandler } from '../lib/oauth/google';
3
3
  import { spotifyEventHandler } from '../lib/oauth/spotify';
4
4
  import { twitchEventHandler } from '../lib/oauth/twitch';
5
5
  import { auth0EventHandler } from '../lib/oauth/auth0';
6
+ import { microsoftEventHandler } from '../lib/oauth/microsoft';
6
7
  import { discordEventHandler } from '../lib/oauth/discord';
7
8
  import { battledotnetEventHandler } from '../lib/oauth/battledotnet';
9
+ import { linkedinEventHandler } from '../lib/oauth/linkedin';
8
10
  export declare const oauth: {
9
11
  githubEventHandler: typeof githubEventHandler;
10
12
  spotifyEventHandler: typeof spotifyEventHandler;
11
13
  googleEventHandler: typeof googleEventHandler;
12
14
  twitchEventHandler: typeof twitchEventHandler;
13
15
  auth0EventHandler: typeof auth0EventHandler;
16
+ microsoftEventHandler: typeof microsoftEventHandler;
14
17
  discordEventHandler: typeof discordEventHandler;
15
18
  battledotnetEventHandler: typeof battledotnetEventHandler;
19
+ linkedinEventHandler: typeof linkedinEventHandler;
16
20
  };
@@ -3,14 +3,18 @@ import { googleEventHandler } from "../lib/oauth/google.mjs";
3
3
  import { spotifyEventHandler } from "../lib/oauth/spotify.mjs";
4
4
  import { twitchEventHandler } from "../lib/oauth/twitch.mjs";
5
5
  import { auth0EventHandler } from "../lib/oauth/auth0.mjs";
6
+ import { microsoftEventHandler } from "../lib/oauth/microsoft.mjs";
6
7
  import { discordEventHandler } from "../lib/oauth/discord.mjs";
7
8
  import { battledotnetEventHandler } from "../lib/oauth/battledotnet.mjs";
9
+ import { linkedinEventHandler } from "../lib/oauth/linkedin.mjs";
8
10
  export const oauth = {
9
11
  githubEventHandler,
10
12
  spotifyEventHandler,
11
13
  googleEventHandler,
12
14
  twitchEventHandler,
13
15
  auth0EventHandler,
16
+ microsoftEventHandler,
14
17
  discordEventHandler,
15
- battledotnetEventHandler
18
+ battledotnetEventHandler,
19
+ linkedinEventHandler
16
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-auth-utils",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Minimalist Auth module for Nuxt with SSR",
5
5
  "repository": "Atinux/nuxt-auth-utils",
6
6
  "license": "MIT",
@@ -36,20 +36,20 @@
36
36
  "ohash": "^1.1.3"
37
37
  },
38
38
  "devDependencies": {
39
- "@iconify-json/simple-icons": "^1.1.79",
39
+ "@iconify-json/simple-icons": "^1.1.82",
40
40
  "@nuxt/devtools": "latest",
41
41
  "@nuxt/eslint-config": "^0.2.0",
42
42
  "@nuxt/module-builder": "^0.5.4",
43
43
  "@nuxt/schema": "^3.8.2",
44
44
  "@nuxt/test-utils": "^3.8.1",
45
- "@nuxt/ui": "^2.10.0",
46
- "@nuxt/ui-pro": "^0.4.2",
47
- "@types/node": "^20.9.3",
45
+ "@nuxt/ui": "^2.11.0",
46
+ "@nuxt/ui-pro": "^0.5.0",
47
+ "@types/node": "^20.10.4",
48
48
  "changelogen": "^0.5.5",
49
- "eslint": "^8.54.0",
49
+ "eslint": "^8.55.0",
50
50
  "nuxt": "^3.8.2",
51
- "typescript": "^5.3.2",
52
- "vitest": "^0.34.6",
53
- "vue-tsc": "^1.8.22"
51
+ "typescript": "^5.3.3",
52
+ "vitest": "^1.0.2",
53
+ "vue-tsc": "^1.8.25"
54
54
  }
55
55
  }