nuxt-auth-utils 0.5.32 → 0.5.34
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 +57 -5
- package/dist/module.json +2 -2
- package/dist/module.mjs +29 -1
- package/dist/runtime/app/components/AuthState.d.vue.ts +20 -0
- package/dist/runtime/app/composables/session.js +8 -3
- package/dist/runtime/app/plugins/session.client.js +8 -4
- package/dist/runtime/server/api/session.delete.d.ts +3 -1
- package/dist/runtime/server/api/session.get.d.ts +1 -1
- package/dist/runtime/server/lib/atproto/bluesky.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/apple.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/apple.js +3 -0
- package/dist/runtime/server/lib/oauth/atlassian.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/auth0.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/authentik.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/azureb2c.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/battledotnet.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/box.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/cloudflare.d.ts +86 -0
- package/dist/runtime/server/lib/oauth/cloudflare.js +72 -0
- package/dist/runtime/server/lib/oauth/cognito.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/discord.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/dropbox.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/facebook.d.ts +14 -3
- package/dist/runtime/server/lib/oauth/facebook.js +15 -3
- package/dist/runtime/server/lib/oauth/gitea.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/github.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/gitlab.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/google.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/heroku.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/hubspot.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/instagram.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/keycloak.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/kick.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/line.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/linear.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/linkedin.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/livechat.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/mastodon.d.ts +62 -0
- package/dist/runtime/server/lib/oauth/mastodon.js +178 -0
- package/dist/runtime/server/lib/oauth/microsoft.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/oidc.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/oidc.js +4 -3
- package/dist/runtime/server/lib/oauth/okta.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/okta.js +1 -1
- package/dist/runtime/server/lib/oauth/ory.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/osu.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/paypal.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/polar.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/riotgames.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/roblox.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/salesforce.d.ts +9 -4
- package/dist/runtime/server/lib/oauth/salesforce.js +8 -4
- package/dist/runtime/server/lib/oauth/seznam.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/shopifyCustomer.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/shopifyCustomer.js +1 -1
- package/dist/runtime/server/lib/oauth/slack.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/spotify.d.ts +49 -2
- package/dist/runtime/server/lib/oauth/steam.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/strava.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/tiktok.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/twitch.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/vk.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/wechat.d.ts +67 -0
- package/dist/runtime/server/lib/oauth/wechat.js +107 -0
- package/dist/runtime/server/lib/oauth/workos.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/x.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/xsuaa.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/yandex.d.ts +1 -1
- package/dist/runtime/server/lib/oauth/zendesk.d.ts +110 -0
- package/dist/runtime/server/lib/oauth/zendesk.js +109 -0
- package/dist/runtime/server/lib/oauth/zitadel.d.ts +1 -1
- package/dist/runtime/server/lib/utils.d.ts +4 -3
- package/dist/runtime/server/lib/utils.js +3 -3
- package/dist/runtime/server/routes/atproto/client-metadata.json.get.d.ts +128 -1
- package/dist/runtime/server/utils/session.js +6 -1
- package/dist/runtime/types/oauth-config.d.ts +1 -1
- package/dist/runtime/types/webauthn.d.ts +4 -2
- package/package.json +17 -22
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthWechatConfig {
|
|
3
|
+
/**
|
|
4
|
+
* WeChat App ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_WECHAT_APP_ID
|
|
6
|
+
*/
|
|
7
|
+
appId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* WeChat App Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_WECHAT_APP_SECRET
|
|
11
|
+
*/
|
|
12
|
+
appSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* WeChat OAuth Scope
|
|
15
|
+
* @default ['snsapi_login']
|
|
16
|
+
* @see https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
|
|
17
|
+
*/
|
|
18
|
+
scope?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* Authorization URL
|
|
21
|
+
* @default 'https://open.weixin.qq.com/connect/qrconnect'
|
|
22
|
+
*/
|
|
23
|
+
authorizationURL?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Access token URL
|
|
26
|
+
* @default 'https://api.weixin.qq.com/sns/oauth2/access_token'
|
|
27
|
+
*/
|
|
28
|
+
tokenURL?: string;
|
|
29
|
+
/**
|
|
30
|
+
* User profile URL
|
|
31
|
+
* @default 'https://api.weixin.qq.com/sns/userinfo'
|
|
32
|
+
*/
|
|
33
|
+
userURL?: string;
|
|
34
|
+
/**
|
|
35
|
+
* User info language.
|
|
36
|
+
* @default 'zh_CN'
|
|
37
|
+
*/
|
|
38
|
+
lang?: 'zh_CN' | 'zh_TW' | 'en';
|
|
39
|
+
/**
|
|
40
|
+
* Redirect URL to allow overriding when public hostname cannot be inferred.
|
|
41
|
+
* @default process.env.NUXT_OAUTH_WECHAT_REDIRECT_URL or current URL
|
|
42
|
+
*/
|
|
43
|
+
redirectURL?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface WechatOAuthTokens {
|
|
46
|
+
access_token: string;
|
|
47
|
+
expires_in: number;
|
|
48
|
+
refresh_token: string;
|
|
49
|
+
openid: string;
|
|
50
|
+
scope: string;
|
|
51
|
+
unionid?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface WechatOAuthUser {
|
|
54
|
+
openid: string;
|
|
55
|
+
nickname: string;
|
|
56
|
+
sex: 0 | 1 | 2;
|
|
57
|
+
province: string;
|
|
58
|
+
city: string;
|
|
59
|
+
country: string;
|
|
60
|
+
headimgurl: string;
|
|
61
|
+
privilege: string[];
|
|
62
|
+
unionid?: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function defineOAuthWechatEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthWechatConfig, {
|
|
65
|
+
user: WechatOAuthUser;
|
|
66
|
+
tokens: WechatOAuthTokens;
|
|
67
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
|
+
import { withQuery } from "ufo";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import {
|
|
5
|
+
getOAuthRedirectURL,
|
|
6
|
+
handleInvalidState,
|
|
7
|
+
handleMissingConfiguration,
|
|
8
|
+
handleState
|
|
9
|
+
} from "../utils.js";
|
|
10
|
+
import { createError, useRuntimeConfig } from "#imports";
|
|
11
|
+
function isWechatOAuthError(value) {
|
|
12
|
+
return Boolean(
|
|
13
|
+
value && typeof value === "object" && "errcode" in value && "errmsg" in value
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
function handleWechatOAuthError(event, phase, oauthError, onError) {
|
|
17
|
+
const error = createError({
|
|
18
|
+
statusCode: 401,
|
|
19
|
+
message: `WeChat ${phase} request failed: ${oauthError.errmsg} (${oauthError.errcode})`,
|
|
20
|
+
data: oauthError
|
|
21
|
+
});
|
|
22
|
+
if (!onError) throw error;
|
|
23
|
+
return onError(event, error);
|
|
24
|
+
}
|
|
25
|
+
export function defineOAuthWechatEventHandler({
|
|
26
|
+
config,
|
|
27
|
+
onSuccess,
|
|
28
|
+
onError
|
|
29
|
+
}) {
|
|
30
|
+
return eventHandler(async (event) => {
|
|
31
|
+
config = defu(config, useRuntimeConfig(event).oauth?.wechat, {
|
|
32
|
+
authorizationURL: "https://open.weixin.qq.com/connect/qrconnect",
|
|
33
|
+
tokenURL: "https://api.weixin.qq.com/sns/oauth2/access_token",
|
|
34
|
+
userURL: "https://api.weixin.qq.com/sns/userinfo",
|
|
35
|
+
lang: "zh_CN"
|
|
36
|
+
});
|
|
37
|
+
const query = getQuery(event);
|
|
38
|
+
if (query.error) {
|
|
39
|
+
const error = createError({
|
|
40
|
+
statusCode: 401,
|
|
41
|
+
message: `WeChat login failed: ${query.error || "Unknown error"}`,
|
|
42
|
+
data: query
|
|
43
|
+
});
|
|
44
|
+
if (!onError) throw error;
|
|
45
|
+
return onError(event, error);
|
|
46
|
+
}
|
|
47
|
+
if (!config.appId || !config.appSecret) {
|
|
48
|
+
return handleMissingConfiguration(event, "wechat", ["appId", "appSecret"], onError);
|
|
49
|
+
}
|
|
50
|
+
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
51
|
+
if (!query.code && query.state) {
|
|
52
|
+
await handleState(event, { isCallback: true });
|
|
53
|
+
const error = createError({
|
|
54
|
+
statusCode: 401,
|
|
55
|
+
message: "WeChat login failed: authorization denied",
|
|
56
|
+
data: query
|
|
57
|
+
});
|
|
58
|
+
if (!onError) throw error;
|
|
59
|
+
return onError(event, error);
|
|
60
|
+
}
|
|
61
|
+
const state = await handleState(event);
|
|
62
|
+
if (!query.code) {
|
|
63
|
+
config.scope = config.scope?.length ? config.scope : ["snsapi_login"];
|
|
64
|
+
return sendRedirect(
|
|
65
|
+
event,
|
|
66
|
+
`${withQuery(config.authorizationURL, {
|
|
67
|
+
appid: config.appId,
|
|
68
|
+
redirect_uri: redirectURL,
|
|
69
|
+
response_type: "code",
|
|
70
|
+
scope: config.scope.join(","),
|
|
71
|
+
state
|
|
72
|
+
})}#wechat_redirect`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (!state || query.state !== state) {
|
|
76
|
+
return handleInvalidState(event, "wechat", onError);
|
|
77
|
+
}
|
|
78
|
+
const tokens = await $fetch(config.tokenURL, {
|
|
79
|
+
// WeChat answers JSON with a text/plain content type
|
|
80
|
+
responseType: "json",
|
|
81
|
+
query: {
|
|
82
|
+
appid: config.appId,
|
|
83
|
+
secret: config.appSecret,
|
|
84
|
+
code: query.code,
|
|
85
|
+
grant_type: "authorization_code"
|
|
86
|
+
}
|
|
87
|
+
}).catch((error) => ({ errcode: error?.response?.status ?? -1, errmsg: "token request failed" }));
|
|
88
|
+
if (isWechatOAuthError(tokens)) {
|
|
89
|
+
return handleWechatOAuthError(event, "token", tokens, onError);
|
|
90
|
+
}
|
|
91
|
+
const user = await $fetch(config.userURL, {
|
|
92
|
+
responseType: "json",
|
|
93
|
+
query: {
|
|
94
|
+
access_token: tokens.access_token,
|
|
95
|
+
openid: tokens.openid,
|
|
96
|
+
lang: config.lang
|
|
97
|
+
}
|
|
98
|
+
}).catch((error) => ({ errcode: error?.response?.status ?? -1, errmsg: "userinfo request failed" }));
|
|
99
|
+
if (isWechatOAuthError(user)) {
|
|
100
|
+
return handleWechatOAuthError(event, "userinfo", user, onError);
|
|
101
|
+
}
|
|
102
|
+
return onSuccess(event, {
|
|
103
|
+
tokens,
|
|
104
|
+
user
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -63,4 +63,4 @@ export interface OAuthWorkOSTokens {
|
|
|
63
63
|
export declare function defineOAuthWorkOSEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthWorkOSConfig, {
|
|
64
64
|
user: OAuthWorkOSUser;
|
|
65
65
|
tokens: OAuthWorkOSTokens;
|
|
66
|
-
}>): any
|
|
66
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -43,4 +43,4 @@ export interface OAuthXConfig {
|
|
|
43
43
|
*/
|
|
44
44
|
redirectURL?: string;
|
|
45
45
|
}
|
|
46
|
-
export declare function defineOAuthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): any
|
|
46
|
+
export declare function defineOAuthXEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthXConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -28,4 +28,4 @@ export interface OAuthXSUAAConfig {
|
|
|
28
28
|
*/
|
|
29
29
|
redirectURL?: string;
|
|
30
30
|
}
|
|
31
|
-
export declare function defineOAuthXSUAAEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthXSUAAConfig>): any
|
|
31
|
+
export declare function defineOAuthXSUAAEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthXSUAAConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -43,4 +43,4 @@ export interface OAuthYandexConfig {
|
|
|
43
43
|
*/
|
|
44
44
|
redirectURL?: string;
|
|
45
45
|
}
|
|
46
|
-
export declare function defineOAuthYandexEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthYandexConfig>): any
|
|
46
|
+
export declare function defineOAuthYandexEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthYandexConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { OAuthConfig } from '#auth-utils';
|
|
2
|
+
export interface OAuthZendeskConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Zendesk OAuth Client ID
|
|
5
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_CLIENT_ID
|
|
6
|
+
*/
|
|
7
|
+
clientId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Zendesk OAuth Client Secret
|
|
10
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_CLIENT_SECRET
|
|
11
|
+
*/
|
|
12
|
+
clientSecret?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Zendesk subdomain, for example `mycompany` for `mycompany.zendesk.com`
|
|
15
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_SUBDOMAIN
|
|
16
|
+
*/
|
|
17
|
+
subdomain?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Zendesk OAuth Scope
|
|
20
|
+
* @default ['read']
|
|
21
|
+
* @see https://support.zendesk.com/hc/en-us/articles/4408845965210-Using-OAuth-authentication-with-your-application
|
|
22
|
+
* @example ['read', 'write']
|
|
23
|
+
*/
|
|
24
|
+
scope?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Redirect URL to allow overriding for situations like prod failing to determine public hostname
|
|
27
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_REDIRECT_URL
|
|
28
|
+
*/
|
|
29
|
+
redirectURL?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Zendesk Marketplace name header value.
|
|
32
|
+
* Only required for apps published in the Zendesk Marketplace.
|
|
33
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_MARKETPLACE_NAME
|
|
34
|
+
*/
|
|
35
|
+
marketplaceName?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Zendesk Marketplace organization ID header value.
|
|
38
|
+
* Only required for apps published in the Zendesk Marketplace.
|
|
39
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_MARKETPLACE_ORG_ID
|
|
40
|
+
*/
|
|
41
|
+
marketplaceOrgId?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Zendesk Marketplace bot ID header value.
|
|
44
|
+
* Only required for marketplace bot integrations.
|
|
45
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_MARKETPLACE_BOT_ID
|
|
46
|
+
*/
|
|
47
|
+
marketplaceBotId?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Zendesk Marketplace app ID header value.
|
|
50
|
+
* Only required for apps published in the Zendesk Marketplace.
|
|
51
|
+
* @default process.env.NUXT_OAUTH_ZENDESK_MARKETPLACE_APP_ID
|
|
52
|
+
*/
|
|
53
|
+
marketplaceAppId?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ZendeskUser {
|
|
56
|
+
id: number;
|
|
57
|
+
url: string;
|
|
58
|
+
name: string;
|
|
59
|
+
email: string;
|
|
60
|
+
created_at: string;
|
|
61
|
+
updated_at: string;
|
|
62
|
+
time_zone: string | null;
|
|
63
|
+
iana_time_zone: string | null;
|
|
64
|
+
phone: string | null;
|
|
65
|
+
shared_phone_number: boolean | null;
|
|
66
|
+
photo: {
|
|
67
|
+
url: string | null;
|
|
68
|
+
content_url: string | null;
|
|
69
|
+
} | null;
|
|
70
|
+
locale_id: number;
|
|
71
|
+
locale: string;
|
|
72
|
+
organization_id: number | null;
|
|
73
|
+
role: string;
|
|
74
|
+
verified: boolean;
|
|
75
|
+
external_id: string | null;
|
|
76
|
+
tags: string[];
|
|
77
|
+
alias: string | null;
|
|
78
|
+
active: boolean;
|
|
79
|
+
shared: boolean;
|
|
80
|
+
shared_agent: boolean;
|
|
81
|
+
last_login_at: string | null;
|
|
82
|
+
two_factor_auth_enabled: boolean;
|
|
83
|
+
signature: string | null;
|
|
84
|
+
details: string | null;
|
|
85
|
+
notes: string | null;
|
|
86
|
+
role_type: number | null;
|
|
87
|
+
custom_role_id: number | null;
|
|
88
|
+
is_billing_admin: boolean;
|
|
89
|
+
moderator: boolean;
|
|
90
|
+
ticket_restriction: string | null;
|
|
91
|
+
only_private_comments: boolean;
|
|
92
|
+
restricted_agent: boolean;
|
|
93
|
+
suspended: boolean;
|
|
94
|
+
default_group_id: number | null;
|
|
95
|
+
report_csv: boolean;
|
|
96
|
+
user_fields: Record<string, unknown>;
|
|
97
|
+
suspension_details: unknown | null;
|
|
98
|
+
}
|
|
99
|
+
export interface ZendeskTokens {
|
|
100
|
+
access_token: string;
|
|
101
|
+
refresh_token?: string;
|
|
102
|
+
token_type: string;
|
|
103
|
+
scope: string;
|
|
104
|
+
expires_in?: number;
|
|
105
|
+
refresh_token_expires_in?: number;
|
|
106
|
+
}
|
|
107
|
+
export declare function defineOAuthZendeskEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthZendeskConfig, {
|
|
108
|
+
user: ZendeskUser;
|
|
109
|
+
tokens: ZendeskTokens;
|
|
110
|
+
}>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { eventHandler, getQuery, sendRedirect } from "h3";
|
|
2
|
+
import { withQuery } from "ufo";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import {
|
|
5
|
+
handleMissingConfiguration,
|
|
6
|
+
handleAccessTokenErrorResponse,
|
|
7
|
+
getOAuthRedirectURL,
|
|
8
|
+
handleInvalidState,
|
|
9
|
+
handleState,
|
|
10
|
+
requestAccessToken
|
|
11
|
+
} from "../utils.js";
|
|
12
|
+
import { useRuntimeConfig } from "#imports";
|
|
13
|
+
function getMarketplaceHeaders(config) {
|
|
14
|
+
const headers = {};
|
|
15
|
+
if (config.marketplaceName) {
|
|
16
|
+
headers["X-Zendesk-Marketplace-Name"] = config.marketplaceName;
|
|
17
|
+
}
|
|
18
|
+
if (config.marketplaceOrgId) {
|
|
19
|
+
headers["X-Zendesk-Marketplace-Organization-Id"] = config.marketplaceOrgId;
|
|
20
|
+
}
|
|
21
|
+
if (config.marketplaceBotId) {
|
|
22
|
+
headers["X-Zendesk-Marketplace-Bot-Id"] = config.marketplaceBotId;
|
|
23
|
+
}
|
|
24
|
+
if (config.marketplaceAppId) {
|
|
25
|
+
headers["X-Zendesk-Marketplace-App-Id"] = config.marketplaceAppId;
|
|
26
|
+
}
|
|
27
|
+
return headers;
|
|
28
|
+
}
|
|
29
|
+
export function defineOAuthZendeskEventHandler({
|
|
30
|
+
config,
|
|
31
|
+
onSuccess,
|
|
32
|
+
onError
|
|
33
|
+
}) {
|
|
34
|
+
return eventHandler(async (event) => {
|
|
35
|
+
const runtimeConfig = useRuntimeConfig(event).oauth?.zendesk;
|
|
36
|
+
config = defu(config, runtimeConfig);
|
|
37
|
+
config.scope = config.scope?.length ? config.scope : ["read"];
|
|
38
|
+
if (!config.scope.includes("read") && !config.scope.includes("users:read")) {
|
|
39
|
+
config.scope.push("users:read");
|
|
40
|
+
}
|
|
41
|
+
if (!config.clientId || !config.clientSecret || !config.subdomain) {
|
|
42
|
+
return handleMissingConfiguration(
|
|
43
|
+
event,
|
|
44
|
+
"zendesk",
|
|
45
|
+
["clientId", "clientSecret", "subdomain"],
|
|
46
|
+
onError
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
const baseURL = `https://${config.subdomain}.zendesk.com`;
|
|
50
|
+
const query = getQuery(event);
|
|
51
|
+
const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
|
|
52
|
+
if (query.error) {
|
|
53
|
+
return handleAccessTokenErrorResponse(
|
|
54
|
+
event,
|
|
55
|
+
"zendesk",
|
|
56
|
+
{
|
|
57
|
+
error: query.error,
|
|
58
|
+
error_description: query.error_description
|
|
59
|
+
},
|
|
60
|
+
onError
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const state = await handleState(event);
|
|
64
|
+
if (!query.code) {
|
|
65
|
+
return sendRedirect(
|
|
66
|
+
event,
|
|
67
|
+
withQuery(`${baseURL}/oauth/authorizations/new`, {
|
|
68
|
+
response_type: "code",
|
|
69
|
+
client_id: config.clientId,
|
|
70
|
+
redirect_uri: redirectURL,
|
|
71
|
+
scope: config.scope.join(" "),
|
|
72
|
+
state
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (!state || query.state !== state) {
|
|
77
|
+
return handleInvalidState(event, "zendesk", onError);
|
|
78
|
+
}
|
|
79
|
+
const marketplaceHeaders = getMarketplaceHeaders(config);
|
|
80
|
+
const tokens = await requestAccessToken(`${baseURL}/oauth/tokens`, {
|
|
81
|
+
headers: {
|
|
82
|
+
// Zendesk documents JSON bodies for the token endpoint
|
|
83
|
+
"Content-Type": "application/json",
|
|
84
|
+
...marketplaceHeaders
|
|
85
|
+
},
|
|
86
|
+
body: {
|
|
87
|
+
grant_type: "authorization_code",
|
|
88
|
+
client_id: config.clientId,
|
|
89
|
+
client_secret: config.clientSecret,
|
|
90
|
+
redirect_uri: redirectURL,
|
|
91
|
+
code: query.code,
|
|
92
|
+
scope: config.scope.join(" ")
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
if (tokens.error) {
|
|
96
|
+
return handleAccessTokenErrorResponse(event, "zendesk", tokens, onError);
|
|
97
|
+
}
|
|
98
|
+
const data = await $fetch(`${baseURL}/api/v2/users/me.json`, {
|
|
99
|
+
headers: {
|
|
100
|
+
Authorization: `Bearer ${tokens.access_token}`,
|
|
101
|
+
...marketplaceHeaders
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return onSuccess(event, {
|
|
105
|
+
user: data.user,
|
|
106
|
+
tokens
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -34,4 +34,4 @@ export interface OAuthZitadelConfig {
|
|
|
34
34
|
*/
|
|
35
35
|
redirectURL?: string;
|
|
36
36
|
}
|
|
37
|
-
export declare function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthZitadelConfig>): any
|
|
37
|
+
export declare function defineOAuthZitadelEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthZitadelConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type H3Event } from 'h3';
|
|
2
2
|
import * as jose from 'jose';
|
|
3
3
|
import type { OAuthProvider, OnError } from '#auth-utils';
|
|
4
|
+
export declare const isDevelopment: boolean;
|
|
4
5
|
export declare function getOAuthRedirectURL(event: H3Event): string;
|
|
5
6
|
/**
|
|
6
7
|
* Request an access token body.
|
|
@@ -66,7 +67,7 @@ export declare function handlePkceVerifier(event: H3Event): Promise<{
|
|
|
66
67
|
code_challenge: string;
|
|
67
68
|
code_challenge_method: string;
|
|
68
69
|
} | {
|
|
69
|
-
code_verifier:
|
|
70
|
+
code_verifier: string | undefined;
|
|
70
71
|
code_challenge?: undefined;
|
|
71
72
|
code_challenge_method?: undefined;
|
|
72
73
|
}>;
|
|
@@ -74,7 +75,7 @@ interface HandleStateOptions {
|
|
|
74
75
|
isCallback?: boolean;
|
|
75
76
|
sameSite?: 'lax' | 'none' | 'strict';
|
|
76
77
|
}
|
|
77
|
-
export declare function handleState(event: H3Event, options?: HandleStateOptions): Promise<
|
|
78
|
+
export declare function handleState(event: H3Event, options?: HandleStateOptions): Promise<string | undefined>;
|
|
78
79
|
export declare function parseJwt(token: string): jose.JWTPayload;
|
|
79
|
-
export declare function handleNonce(event: H3Event):
|
|
80
|
+
export declare function handleNonce(event: H3Event): string | undefined;
|
|
80
81
|
export {};
|
|
@@ -5,7 +5,7 @@ import { snakeCase, upperFirst } from "scule";
|
|
|
5
5
|
import * as jose from "jose";
|
|
6
6
|
import { subtle, getRandomValues } from "uncrypto";
|
|
7
7
|
import { createError } from "#imports";
|
|
8
|
-
const isDevelopment = process.env.NODE_ENV === "development";
|
|
8
|
+
export const isDevelopment = process.env.NODE_ENV === "development";
|
|
9
9
|
const OAUTH_COOKIE_MAX_AGE = 60 * 10;
|
|
10
10
|
export function getOAuthRedirectURL(event) {
|
|
11
11
|
const requestURL = getRequestURL(event);
|
|
@@ -24,14 +24,14 @@ export async function requestAccessToken(url, options) {
|
|
|
24
24
|
headers,
|
|
25
25
|
body
|
|
26
26
|
}).catch((error) => {
|
|
27
|
-
if (error instanceof FetchError && error.status
|
|
27
|
+
if (error instanceof FetchError && error.status && error.status >= 400 && error.status < 500 && error.data?.error) {
|
|
28
28
|
return error.data;
|
|
29
29
|
}
|
|
30
30
|
throw error;
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
export function handleAccessTokenErrorResponse(event, oauthProvider, oauthError, onError) {
|
|
34
|
-
const message = `${upperFirst(oauthProvider)} login failed: ${oauthError.error_description || oauthError.error || "Unknown error"}`;
|
|
34
|
+
const message = `${upperFirst(oauthProvider)} login failed: ${oauthError.error_description || oauthError.error?.message || oauthError.error || "Unknown error"}`;
|
|
35
35
|
const error = createError({
|
|
36
36
|
statusCode: 401,
|
|
37
37
|
message,
|
|
@@ -1,2 +1,129 @@
|
|
|
1
|
-
declare const _default:
|
|
1
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, {
|
|
2
|
+
redirect_uris: [string, ...string[]];
|
|
3
|
+
scope?: string | undefined;
|
|
4
|
+
response_types?: ["code" | "none" | "token" | "code id_token token" | "code id_token" | "code token" | "id_token token" | "id_token", ...("code" | "none" | "token" | "code id_token token" | "code id_token" | "code token" | "id_token token" | "id_token")[]] | undefined;
|
|
5
|
+
grant_types?: ["authorization_code" | "implicit" | "refresh_token" | "password" | "client_credentials" | "urn:ietf:params:oauth:grant-type:jwt-bearer" | "urn:ietf:params:oauth:grant-type:saml2-bearer", ...("authorization_code" | "implicit" | "refresh_token" | "password" | "client_credentials" | "urn:ietf:params:oauth:grant-type:jwt-bearer" | "urn:ietf:params:oauth:grant-type:saml2-bearer")[]] | undefined;
|
|
6
|
+
token_endpoint_auth_method?: "client_secret_basic" | "client_secret_jwt" | "client_secret_post" | "none" | "private_key_jwt" | "self_signed_tls_client_auth" | "tls_client_auth" | undefined;
|
|
7
|
+
token_endpoint_auth_signing_alg?: string | undefined;
|
|
8
|
+
userinfo_signed_response_alg?: string | undefined;
|
|
9
|
+
userinfo_encrypted_response_alg?: string | undefined;
|
|
10
|
+
jwks_uri?: string | undefined;
|
|
11
|
+
jwks?: {
|
|
12
|
+
keys: ({
|
|
13
|
+
kty: "RSA";
|
|
14
|
+
n: string;
|
|
15
|
+
e: string;
|
|
16
|
+
alg?: "RS256" | "RS384" | "RS512" | "PS256" | "PS384" | "PS512" | undefined;
|
|
17
|
+
kid?: string | undefined;
|
|
18
|
+
ext?: boolean | undefined;
|
|
19
|
+
use?: "sig" | "enc" | undefined;
|
|
20
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
21
|
+
x5c?: string[] | undefined;
|
|
22
|
+
x5t?: string | undefined;
|
|
23
|
+
"x5t#S256"?: string | undefined;
|
|
24
|
+
x5u?: string | undefined;
|
|
25
|
+
d?: string | undefined;
|
|
26
|
+
p?: string | undefined;
|
|
27
|
+
q?: string | undefined;
|
|
28
|
+
dp?: string | undefined;
|
|
29
|
+
dq?: string | undefined;
|
|
30
|
+
qi?: string | undefined;
|
|
31
|
+
oth?: [{
|
|
32
|
+
d?: string | undefined;
|
|
33
|
+
r?: string | undefined;
|
|
34
|
+
t?: string | undefined;
|
|
35
|
+
}, ...{
|
|
36
|
+
d?: string | undefined;
|
|
37
|
+
r?: string | undefined;
|
|
38
|
+
t?: string | undefined;
|
|
39
|
+
}[]] | undefined;
|
|
40
|
+
} | {
|
|
41
|
+
kty: "EC";
|
|
42
|
+
crv: "P-256" | "P-384" | "P-521";
|
|
43
|
+
x: string;
|
|
44
|
+
y: string;
|
|
45
|
+
alg?: "ES256" | "ES384" | "ES512" | undefined;
|
|
46
|
+
kid?: string | undefined;
|
|
47
|
+
ext?: boolean | undefined;
|
|
48
|
+
use?: "sig" | "enc" | undefined;
|
|
49
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
50
|
+
x5c?: string[] | undefined;
|
|
51
|
+
x5t?: string | undefined;
|
|
52
|
+
"x5t#S256"?: string | undefined;
|
|
53
|
+
x5u?: string | undefined;
|
|
54
|
+
d?: string | undefined;
|
|
55
|
+
} | {
|
|
56
|
+
kty: "EC";
|
|
57
|
+
crv: "secp256k1";
|
|
58
|
+
x: string;
|
|
59
|
+
y: string;
|
|
60
|
+
alg?: "ES256K" | undefined;
|
|
61
|
+
kid?: string | undefined;
|
|
62
|
+
ext?: boolean | undefined;
|
|
63
|
+
use?: "sig" | "enc" | undefined;
|
|
64
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
65
|
+
x5c?: string[] | undefined;
|
|
66
|
+
x5t?: string | undefined;
|
|
67
|
+
"x5t#S256"?: string | undefined;
|
|
68
|
+
x5u?: string | undefined;
|
|
69
|
+
d?: string | undefined;
|
|
70
|
+
} | {
|
|
71
|
+
kty: "OKP";
|
|
72
|
+
crv: "Ed25519" | "Ed448";
|
|
73
|
+
x: string;
|
|
74
|
+
alg?: "EdDSA" | undefined;
|
|
75
|
+
kid?: string | undefined;
|
|
76
|
+
ext?: boolean | undefined;
|
|
77
|
+
use?: "sig" | "enc" | undefined;
|
|
78
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
79
|
+
x5c?: string[] | undefined;
|
|
80
|
+
x5t?: string | undefined;
|
|
81
|
+
"x5t#S256"?: string | undefined;
|
|
82
|
+
x5u?: string | undefined;
|
|
83
|
+
d?: string | undefined;
|
|
84
|
+
} | {
|
|
85
|
+
kty: "oct";
|
|
86
|
+
k: string;
|
|
87
|
+
alg?: "HS256" | "HS384" | "HS512" | undefined;
|
|
88
|
+
kid?: string | undefined;
|
|
89
|
+
ext?: boolean | undefined;
|
|
90
|
+
use?: "sig" | "enc" | undefined;
|
|
91
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
92
|
+
x5c?: string[] | undefined;
|
|
93
|
+
x5t?: string | undefined;
|
|
94
|
+
"x5t#S256"?: string | undefined;
|
|
95
|
+
x5u?: string | undefined;
|
|
96
|
+
} | {
|
|
97
|
+
kty: string;
|
|
98
|
+
alg?: string | undefined;
|
|
99
|
+
kid?: string | undefined;
|
|
100
|
+
ext?: boolean | undefined;
|
|
101
|
+
use?: "sig" | "enc" | undefined;
|
|
102
|
+
key_ops?: ("sign" | "verify" | "encrypt" | "decrypt" | "wrapKey" | "unwrapKey" | "deriveKey" | "deriveBits")[] | undefined;
|
|
103
|
+
x5c?: string[] | undefined;
|
|
104
|
+
x5t?: string | undefined;
|
|
105
|
+
"x5t#S256"?: string | undefined;
|
|
106
|
+
x5u?: string | undefined;
|
|
107
|
+
})[];
|
|
108
|
+
} | undefined;
|
|
109
|
+
application_type?: "web" | "native" | undefined;
|
|
110
|
+
subject_type?: "public" | "pairwise" | undefined;
|
|
111
|
+
request_object_signing_alg?: string | undefined;
|
|
112
|
+
id_token_signed_response_alg?: string | undefined;
|
|
113
|
+
authorization_signed_response_alg?: string | undefined;
|
|
114
|
+
authorization_encrypted_response_enc?: "A128CBC-HS256" | undefined;
|
|
115
|
+
authorization_encrypted_response_alg?: string | undefined;
|
|
116
|
+
client_id?: string | undefined;
|
|
117
|
+
client_name?: string | undefined;
|
|
118
|
+
client_uri?: string | undefined;
|
|
119
|
+
policy_uri?: string | undefined;
|
|
120
|
+
tos_uri?: string | undefined;
|
|
121
|
+
logo_uri?: string | undefined;
|
|
122
|
+
default_max_age?: number | undefined;
|
|
123
|
+
require_auth_time?: boolean | undefined;
|
|
124
|
+
contacts?: string[] | undefined;
|
|
125
|
+
tls_client_certificate_bound_access_tokens?: boolean | undefined;
|
|
126
|
+
dpop_bound_access_tokens?: boolean | undefined;
|
|
127
|
+
authorization_details_types?: string[] | undefined;
|
|
128
|
+
}>;
|
|
2
129
|
export default _default;
|
|
@@ -18,7 +18,12 @@ export async function setUserSession(event, data, config) {
|
|
|
18
18
|
export async function replaceUserSession(event, data, config) {
|
|
19
19
|
const session = await _useSession(event, config);
|
|
20
20
|
await session.clear();
|
|
21
|
-
await session.update(
|
|
21
|
+
await session.update((oldData) => {
|
|
22
|
+
for (const key of Object.keys(oldData)) {
|
|
23
|
+
Reflect.deleteProperty(oldData, key);
|
|
24
|
+
}
|
|
25
|
+
return data;
|
|
26
|
+
});
|
|
22
27
|
return session.data;
|
|
23
28
|
}
|
|
24
29
|
export async function clearUserSession(event, config) {
|
|
@@ -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' | 'riotgames' | 'box' | (string & {});
|
|
3
|
+
export type OAuthProvider = ATProtoProvider | 'atlassian' | 'auth0' | 'authentik' | 'azureb2c' | 'battledotnet' | 'cloudflare' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'gitea' | 'github' | 'gitlab' | 'google' | 'hubspot' | 'instagram' | 'kick' | 'keycloak' | 'line' | 'linear' | 'linkedin' | 'mastodon' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'wechat' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | 'apple' | 'livechat' | 'salesforce' | 'slack' | 'heroku' | 'roblox' | 'okta' | 'ory' | 'shopifyCustomer' | 'oidc' | 'osu' | 'riotgames' | 'box' | 'zendesk' | (string & {});
|
|
4
4
|
export type OnError = (event: H3Event, error: H3Error) => Promise<void> | void;
|
|
5
5
|
export interface OAuthConfig<TConfig, TResult = {
|
|
6
6
|
user: any;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { AuthenticationResponseJSON, AuthenticatorTransportFuture, RegistrationResponseJSON } from '@simplewebauthn/types';
|
|
2
1
|
import type { Ref } from 'vue';
|
|
3
2
|
import type { H3Event, H3Error, ValidateResult } from 'h3';
|
|
4
|
-
import type { GenerateAuthenticationOptionsOpts, GenerateRegistrationOptionsOpts, VerifiedAuthenticationResponse, VerifiedRegistrationResponse } from '@simplewebauthn/server';
|
|
3
|
+
import type { GenerateAuthenticationOptionsOpts, GenerateRegistrationOptionsOpts, VerifiedAuthenticationResponse, VerifiedRegistrationResponse, verifyAuthenticationResponse, verifyRegistrationResponse } from '@simplewebauthn/server';
|
|
4
|
+
type RegistrationResponseJSON = Parameters<typeof verifyRegistrationResponse>[0]['response'];
|
|
5
|
+
type AuthenticationResponseJSON = Parameters<typeof verifyAuthenticationResponse>[0]['response'];
|
|
6
|
+
type AuthenticatorTransportFuture = NonNullable<Parameters<typeof verifyAuthenticationResponse>[0]['credential']['transports']>[number];
|
|
5
7
|
export interface WebAuthnCredential {
|
|
6
8
|
id: string;
|
|
7
9
|
publicKey: string;
|