nuxt-auth-utils 0.0.13 → 0.0.15
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 +2 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +12 -0
- package/dist/runtime/server/lib/oauth/auth0.d.ts +7 -0
- package/dist/runtime/server/lib/oauth/auth0.mjs +2 -1
- package/dist/runtime/server/lib/oauth/cognito.d.ts +29 -0
- package/dist/runtime/server/lib/oauth/cognito.mjs +68 -0
- package/dist/runtime/server/lib/oauth/github.mjs +1 -1
- package/dist/runtime/server/lib/oauth/keycloak.d.ts +32 -0
- package/dist/runtime/server/lib/oauth/keycloak.mjs +114 -0
- package/dist/runtime/server/lib/oauth/microsoft.mjs +1 -1
- package/dist/runtime/server/lib/oauth/spotify.mjs +1 -1
- package/dist/runtime/server/lib/oauth/twitch.mjs +1 -1
- package/dist/runtime/server/utils/oauth.d.ts +4 -0
- package/dist/runtime/server/utils/oauth.mjs +5 -1
- package/dist/types.d.mts +2 -2
- package/package.json +14 -14
package/README.md
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -98,10 +98,22 @@ const module = defineNuxtModule({
|
|
|
98
98
|
clientId: "",
|
|
99
99
|
clientSecret: ""
|
|
100
100
|
});
|
|
101
|
+
runtimeConfig.oauth.keycloak = defu(runtimeConfig.oauth.keycloak, {
|
|
102
|
+
clientId: "",
|
|
103
|
+
clientSecret: "",
|
|
104
|
+
serverUrl: "",
|
|
105
|
+
realm: ""
|
|
106
|
+
});
|
|
101
107
|
runtimeConfig.oauth.linkedin = defu(runtimeConfig.oauth.linkedin, {
|
|
102
108
|
clientId: "",
|
|
103
109
|
clientSecret: ""
|
|
104
110
|
});
|
|
111
|
+
runtimeConfig.oauth.cognito = defu(runtimeConfig.oauth.cognito, {
|
|
112
|
+
clientId: "",
|
|
113
|
+
clientSecret: "",
|
|
114
|
+
region: "",
|
|
115
|
+
userPoolId: ""
|
|
116
|
+
});
|
|
105
117
|
}
|
|
106
118
|
});
|
|
107
119
|
|
|
@@ -38,5 +38,12 @@ export interface OAuthAuth0Config {
|
|
|
38
38
|
* @see https://auth0.com/docs/authenticate/login/max-age-reauthentication
|
|
39
39
|
*/
|
|
40
40
|
maxAge?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Login connection. If no connection is specified, it will redirect to the standard Auth0 login page and show the Login Widget.
|
|
43
|
+
* @default ''
|
|
44
|
+
* @see https://auth0.com/docs/api/authentication#social
|
|
45
|
+
* @example 'github'
|
|
46
|
+
*/
|
|
47
|
+
connection?: string;
|
|
41
48
|
}
|
|
42
49
|
export declare function auth0EventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthAuth0Config>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -32,7 +32,8 @@ export function auth0EventHandler({ config, onSuccess, onError }) {
|
|
|
32
32
|
redirect_uri: redirectUrl,
|
|
33
33
|
scope: config.scope.join(" "),
|
|
34
34
|
audience: config.audience || "",
|
|
35
|
-
max_age: config.maxAge || 0
|
|
35
|
+
max_age: config.maxAge || 0,
|
|
36
|
+
connection: config.connection || ""
|
|
36
37
|
})
|
|
37
38
|
);
|
|
38
39
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthCognitoConfig {
|
|
3
|
+
/**
|
|
4
|
+
* AWS Cognito App Client ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_COGNITO_CLIENT_ID
|
|
6
|
+
*/
|
|
7
|
+
clientId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* AWS Cognito App Client Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_COGNITO_CLIENT_SECRET
|
|
11
|
+
*/
|
|
12
|
+
clientSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* AWS Cognito User Pool ID
|
|
15
|
+
* @default process.env.NUXT_OAUTH_COGNITO_USER_POOL_ID
|
|
16
|
+
*/
|
|
17
|
+
userPoolId?: string;
|
|
18
|
+
/**
|
|
19
|
+
* AWS Cognito Region
|
|
20
|
+
* @default process.env.NUXT_OAUTH_COGNITO_REGION
|
|
21
|
+
*/
|
|
22
|
+
region?: string;
|
|
23
|
+
/**
|
|
24
|
+
* AWS Cognito Scope
|
|
25
|
+
* @default []
|
|
26
|
+
*/
|
|
27
|
+
scope?: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function cognitoEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthCognitoConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,68 @@
|
|
|
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 cognitoEventHandler({ config, onSuccess, onError }) {
|
|
7
|
+
return eventHandler(async (event) => {
|
|
8
|
+
config = defu(config, useRuntimeConfig(event).oauth?.cognito);
|
|
9
|
+
const { code } = getQuery(event);
|
|
10
|
+
if (!config.clientId || !config.clientSecret || !config.userPoolId || !config.region) {
|
|
11
|
+
const error = createError({
|
|
12
|
+
statusCode: 500,
|
|
13
|
+
message: "Missing NUXT_OAUTH_COGNITO_CLIENT_ID, NUXT_OAUTH_COGNITO_CLIENT_SECRET, NUXT_OAUTH_COGNITO_USER_POOL_ID, or NUXT_OAUTH_COGNITO_REGION env variables."
|
|
14
|
+
});
|
|
15
|
+
if (!onError)
|
|
16
|
+
throw error;
|
|
17
|
+
return onError(event, error);
|
|
18
|
+
}
|
|
19
|
+
const authorizationURL = `https://${config.userPoolId}.auth.${config.region}.amazoncognito.com/oauth2/authorize`;
|
|
20
|
+
const tokenURL = `https://${config.userPoolId}.auth.${config.region}.amazoncognito.com/oauth2/token`;
|
|
21
|
+
const redirectUrl = getRequestURL(event).href;
|
|
22
|
+
if (!code) {
|
|
23
|
+
config.scope = config.scope || ["openid", "profile"];
|
|
24
|
+
return sendRedirect(
|
|
25
|
+
event,
|
|
26
|
+
withQuery(authorizationURL, {
|
|
27
|
+
client_id: config.clientId,
|
|
28
|
+
redirect_uri: redirectUrl,
|
|
29
|
+
response_type: "code",
|
|
30
|
+
scope: config.scope.join(" ")
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const tokens = await ofetch(
|
|
35
|
+
tokenURL,
|
|
36
|
+
{
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers: {
|
|
39
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
40
|
+
},
|
|
41
|
+
body: `grant_type=authorization_code&client_id=${config.clientId}&client_secret=${config.clientSecret}&redirect_uri=${parsePath(redirectUrl).pathname}&code=${code}`
|
|
42
|
+
}
|
|
43
|
+
).catch((error) => {
|
|
44
|
+
return { error };
|
|
45
|
+
});
|
|
46
|
+
if (tokens.error) {
|
|
47
|
+
const error = createError({
|
|
48
|
+
statusCode: 401,
|
|
49
|
+
message: `Cognito login failed: ${tokens.error_description || "Unknown error"}`,
|
|
50
|
+
data: tokens
|
|
51
|
+
});
|
|
52
|
+
if (!onError)
|
|
53
|
+
throw error;
|
|
54
|
+
return onError(event, error);
|
|
55
|
+
}
|
|
56
|
+
const tokenType = tokens.token_type;
|
|
57
|
+
const accessToken = tokens.access_token;
|
|
58
|
+
const user = await ofetch(`https://${config.userPoolId}.auth.${config.region}.amazoncognito.com/oauth2/userInfo`, {
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: `${tokenType} ${accessToken}`
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return onSuccess(event, {
|
|
64
|
+
tokens,
|
|
65
|
+
user
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthKeycloakConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Keycloak OAuth Client ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_KEYCLOAK_CLIENT_ID
|
|
6
|
+
*/
|
|
7
|
+
clientId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Keycloak OAuth Client Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_KEYCLOAK_CLIENT_SECRET
|
|
11
|
+
*/
|
|
12
|
+
clientSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Keycloak OAuth Server URL
|
|
15
|
+
* @example http://192.168.1.10:8080/auth
|
|
16
|
+
* @default process.env.NUXT_OAUTH_KEYCLOAK_SERVER_URL
|
|
17
|
+
*/
|
|
18
|
+
serverUrl?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Keycloak OAuth Realm
|
|
21
|
+
* @default process.env.NUXT_OAUTH_KEYCLOAK_REALM
|
|
22
|
+
*/
|
|
23
|
+
realm?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Keycloak OAuth Scope
|
|
26
|
+
* @default []
|
|
27
|
+
* @see https://www.keycloak.org/docs/latest/authorization_services/
|
|
28
|
+
* @example ['openid']
|
|
29
|
+
*/
|
|
30
|
+
scope?: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function keycloakEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthKeycloakConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
eventHandler,
|
|
3
|
+
createError,
|
|
4
|
+
getQuery,
|
|
5
|
+
getRequestURL,
|
|
6
|
+
sendRedirect
|
|
7
|
+
} from "h3";
|
|
8
|
+
import { ofetch } from "ofetch";
|
|
9
|
+
import { withQuery, parsePath } from "ufo";
|
|
10
|
+
import { defu } from "defu";
|
|
11
|
+
import { useRuntimeConfig } from "#imports";
|
|
12
|
+
export function keycloakEventHandler({
|
|
13
|
+
config,
|
|
14
|
+
onSuccess,
|
|
15
|
+
onError
|
|
16
|
+
}) {
|
|
17
|
+
return eventHandler(async (event) => {
|
|
18
|
+
config = defu(
|
|
19
|
+
config,
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
useRuntimeConfig(event).oauth?.keycloak
|
|
22
|
+
);
|
|
23
|
+
const query = getQuery(event);
|
|
24
|
+
const { code } = query;
|
|
25
|
+
if (query.error) {
|
|
26
|
+
const error = createError({
|
|
27
|
+
statusCode: 401,
|
|
28
|
+
message: `Keycloak login failed: ${query.error || "Unknown error"}`,
|
|
29
|
+
data: query
|
|
30
|
+
});
|
|
31
|
+
if (!onError)
|
|
32
|
+
throw error;
|
|
33
|
+
return onError(event, error);
|
|
34
|
+
}
|
|
35
|
+
if (!config.clientId || !config.clientSecret || !config.serverUrl || !config.realm) {
|
|
36
|
+
const error = createError({
|
|
37
|
+
statusCode: 500,
|
|
38
|
+
message: "Missing NUXT_OAUTH_KEYCLOAK_CLIENT_ID or NUXT_OAUTH_KEYCLOAK_CLIENT_SECRET or NUXT_OAUTH_KEYCLOAK_SERVER_URL or NUXT_OAUTH_KEYCLOAK_REALM env variables."
|
|
39
|
+
});
|
|
40
|
+
if (!onError)
|
|
41
|
+
throw error;
|
|
42
|
+
return onError(event, error);
|
|
43
|
+
}
|
|
44
|
+
const realmURL = `${config.serverUrl}/realms/${config.realm}`;
|
|
45
|
+
const authorizationURL = `${realmURL}/protocol/openid-connect/auth`;
|
|
46
|
+
const tokenURL = `${realmURL}/protocol/openid-connect/token`;
|
|
47
|
+
const redirectUrl = getRequestURL(event).href;
|
|
48
|
+
if (!code) {
|
|
49
|
+
config.scope = config.scope || ["openid"];
|
|
50
|
+
return sendRedirect(
|
|
51
|
+
event,
|
|
52
|
+
withQuery(authorizationURL, {
|
|
53
|
+
client_id: config.clientId,
|
|
54
|
+
redirect_uri: redirectUrl,
|
|
55
|
+
scope: config.scope.join(" "),
|
|
56
|
+
response_type: "code"
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
config.scope = config.scope || [];
|
|
61
|
+
if (!config.scope.includes("openid")) {
|
|
62
|
+
config.scope.push("openid");
|
|
63
|
+
}
|
|
64
|
+
const tokens = await ofetch(tokenURL, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
68
|
+
},
|
|
69
|
+
body: new URLSearchParams({
|
|
70
|
+
client_id: config.clientId,
|
|
71
|
+
client_secret: config.clientSecret,
|
|
72
|
+
grant_type: "authorization_code",
|
|
73
|
+
redirect_uri: parsePath(redirectUrl).pathname,
|
|
74
|
+
code
|
|
75
|
+
}).toString()
|
|
76
|
+
}).catch((error) => {
|
|
77
|
+
return { error };
|
|
78
|
+
});
|
|
79
|
+
if (tokens.error) {
|
|
80
|
+
const error = createError({
|
|
81
|
+
statusCode: 401,
|
|
82
|
+
message: `Keycloak login failed: ${tokens.error?.data?.error_description || "Unknown error"}`,
|
|
83
|
+
data: tokens
|
|
84
|
+
});
|
|
85
|
+
if (!onError)
|
|
86
|
+
throw error;
|
|
87
|
+
return onError(event, error);
|
|
88
|
+
}
|
|
89
|
+
const accessToken = tokens.access_token;
|
|
90
|
+
const user = await ofetch(
|
|
91
|
+
`${realmURL}/protocol/openid-connect/userinfo`,
|
|
92
|
+
{
|
|
93
|
+
headers: {
|
|
94
|
+
Authorization: `Bearer ${accessToken}`,
|
|
95
|
+
Accept: "application/json"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
if (!user) {
|
|
100
|
+
const error = createError({
|
|
101
|
+
statusCode: 500,
|
|
102
|
+
message: "Could not get Keycloak user",
|
|
103
|
+
data: tokens
|
|
104
|
+
});
|
|
105
|
+
if (!onError)
|
|
106
|
+
throw error;
|
|
107
|
+
return onError(event, error);
|
|
108
|
+
}
|
|
109
|
+
return onSuccess(event, {
|
|
110
|
+
user,
|
|
111
|
+
tokens
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
@@ -6,7 +6,9 @@ import { auth0EventHandler } from '../lib/oauth/auth0';
|
|
|
6
6
|
import { microsoftEventHandler } from '../lib/oauth/microsoft';
|
|
7
7
|
import { discordEventHandler } from '../lib/oauth/discord';
|
|
8
8
|
import { battledotnetEventHandler } from '../lib/oauth/battledotnet';
|
|
9
|
+
import { keycloakEventHandler } from '../lib/oauth/keycloak';
|
|
9
10
|
import { linkedinEventHandler } from '../lib/oauth/linkedin';
|
|
11
|
+
import { cognitoEventHandler } from '../lib/oauth/cognito';
|
|
10
12
|
export declare const oauth: {
|
|
11
13
|
githubEventHandler: typeof githubEventHandler;
|
|
12
14
|
spotifyEventHandler: typeof spotifyEventHandler;
|
|
@@ -16,5 +18,7 @@ export declare const oauth: {
|
|
|
16
18
|
microsoftEventHandler: typeof microsoftEventHandler;
|
|
17
19
|
discordEventHandler: typeof discordEventHandler;
|
|
18
20
|
battledotnetEventHandler: typeof battledotnetEventHandler;
|
|
21
|
+
keycloakEventHandler: typeof keycloakEventHandler;
|
|
19
22
|
linkedinEventHandler: typeof linkedinEventHandler;
|
|
23
|
+
cognitoEventHandler: typeof cognitoEventHandler;
|
|
20
24
|
};
|
|
@@ -6,7 +6,9 @@ import { auth0EventHandler } from "../lib/oauth/auth0.mjs";
|
|
|
6
6
|
import { microsoftEventHandler } from "../lib/oauth/microsoft.mjs";
|
|
7
7
|
import { discordEventHandler } from "../lib/oauth/discord.mjs";
|
|
8
8
|
import { battledotnetEventHandler } from "../lib/oauth/battledotnet.mjs";
|
|
9
|
+
import { keycloakEventHandler } from "../lib/oauth/keycloak.mjs";
|
|
9
10
|
import { linkedinEventHandler } from "../lib/oauth/linkedin.mjs";
|
|
11
|
+
import { cognitoEventHandler } from "../lib/oauth/cognito.mjs";
|
|
10
12
|
export const oauth = {
|
|
11
13
|
githubEventHandler,
|
|
12
14
|
spotifyEventHandler,
|
|
@@ -16,5 +18,7 @@ export const oauth = {
|
|
|
16
18
|
microsoftEventHandler,
|
|
17
19
|
discordEventHandler,
|
|
18
20
|
battledotnetEventHandler,
|
|
19
|
-
|
|
21
|
+
keycloakEventHandler,
|
|
22
|
+
linkedinEventHandler,
|
|
23
|
+
cognitoEventHandler
|
|
20
24
|
};
|
package/dist/types.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import type { ModuleOptions } from './module'
|
|
2
|
+
import type { ModuleOptions } from './module.js'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
declare module '@nuxt/schema' {
|
|
@@ -13,4 +13,4 @@ declare module 'nuxt/schema' {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
export type { ModuleOptions, default } from './module'
|
|
16
|
+
export type { ModuleOptions, default } from './module.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-auth-utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Minimalist Auth module for Nuxt with SSR",
|
|
5
5
|
"repository": "Atinux/nuxt-auth-utils",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,27 +30,27 @@
|
|
|
30
30
|
"test:watch": "vitest watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@nuxt/kit": "^3.
|
|
34
|
-
"defu": "^6.1.
|
|
33
|
+
"@nuxt/kit": "^3.9.3",
|
|
34
|
+
"defu": "^6.1.4",
|
|
35
35
|
"hookable": "^5.5.3",
|
|
36
36
|
"ofetch": "^1.3.3",
|
|
37
37
|
"ohash": "^1.1.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@iconify-json/simple-icons": "^1.1.
|
|
40
|
+
"@iconify-json/simple-icons": "^1.1.90",
|
|
41
41
|
"@nuxt/devtools": "latest",
|
|
42
42
|
"@nuxt/eslint-config": "^0.2.0",
|
|
43
|
-
"@nuxt/module-builder": "^0.5.
|
|
44
|
-
"@nuxt/schema": "^3.
|
|
45
|
-
"@nuxt/test-utils": "^3.
|
|
46
|
-
"@nuxt/ui": "^2.
|
|
47
|
-
"@nuxt/ui-pro": "^0.
|
|
48
|
-
"@types/node": "^20.10
|
|
43
|
+
"@nuxt/module-builder": "^0.5.5",
|
|
44
|
+
"@nuxt/schema": "^3.9.3",
|
|
45
|
+
"@nuxt/test-utils": "^3.11.0",
|
|
46
|
+
"@nuxt/ui": "^2.12.3",
|
|
47
|
+
"@nuxt/ui-pro": "^0.7.3",
|
|
48
|
+
"@types/node": "^20.11.10",
|
|
49
49
|
"changelogen": "^0.5.5",
|
|
50
|
-
"eslint": "^8.
|
|
51
|
-
"nuxt": "^3.
|
|
50
|
+
"eslint": "^8.56.0",
|
|
51
|
+
"nuxt": "^3.9.3",
|
|
52
52
|
"typescript": "^5.3.3",
|
|
53
|
-
"vitest": "^1.
|
|
54
|
-
"vue-tsc": "^1.8.
|
|
53
|
+
"vitest": "^1.2.2",
|
|
54
|
+
"vue-tsc": "^1.8.27"
|
|
55
55
|
}
|
|
56
56
|
}
|