nuxt-auth-utils 0.5.6 → 0.5.7

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
@@ -214,6 +214,7 @@ It can also be set using environment variables:
214
214
  - GitHub
215
215
  - GitLab
216
216
  - Google
217
+ - Hubspot
217
218
  - Instagram
218
219
  - Keycloak
219
220
  - Linear
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.5.6",
4
+ "version": "0.5.7",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -157,6 +157,7 @@ const module = defineNuxtModule({
157
157
  clientId: "",
158
158
  clientSecret: "",
159
159
  serverUrl: "",
160
+ serverUrlInternal: "",
160
161
  realm: "",
161
162
  redirectURL: ""
162
163
  });
@@ -254,6 +255,11 @@ const module = defineNuxtModule({
254
255
  clientSecret: "",
255
256
  redirectURL: ""
256
257
  });
258
+ runtimeConfig.oauth.hubspot = defu(runtimeConfig.oauth.hubspot, {
259
+ clientId: "",
260
+ clientSecret: "",
261
+ redirectURL: ""
262
+ });
257
263
  }
258
264
  });
259
265
 
@@ -1,2 +1,2 @@
1
- declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: any;
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: any;
2
2
  export default _default;
@@ -35,10 +35,5 @@ export interface OAuthCognitoConfig {
35
35
  * @default process.env.NUXT_OAUTH_COGNITO_REDIRECT_URL or current URL
36
36
  */
37
37
  redirectURL?: string;
38
- /**
39
- * AWS Cognito App Custom Domain – some pool configurations require this
40
- * @default ''
41
- */
42
- domain?: string;
43
38
  }
44
39
  export declare function defineOAuthCognitoEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthCognitoConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -1,7 +1,8 @@
1
+ import { defu } from "defu";
1
2
  import { eventHandler, getQuery, sendRedirect } from "h3";
3
+ import { discovery } from "openid-client";
2
4
  import { withQuery } from "ufo";
3
- import { defu } from "defu";
4
- import { handleMissingConfiguration, handleAccessTokenErrorResponse, getOAuthRedirectURL, requestAccessToken } from "../utils.js";
5
+ import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleMissingConfiguration, requestAccessToken } from "../utils.js";
5
6
  import { useRuntimeConfig } from "#imports";
6
7
  export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
7
8
  return eventHandler(async (event) => {
@@ -11,9 +12,16 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
11
12
  if (!config.clientId || !config.clientSecret || !config.userPoolId || !config.region) {
12
13
  return handleMissingConfiguration(event, "cognito", ["clientId", "clientSecret", "userPoolId", "region"], onError);
13
14
  }
14
- const urlBase = config?.domain || `${config.userPoolId}.auth.${config.region}.amazoncognito.com`;
15
- const authorizationURL = `https://${urlBase}/oauth2/authorize`;
16
- const tokenURL = `https://${urlBase}/oauth2/token`;
15
+ const congitoDiscoveryUrl = new URL(`https://cognito-idp.${config.region}.amazonaws.com/${config.userPoolId}/.well-known/openid-configuration`);
16
+ const issuer = await discovery(congitoDiscoveryUrl, config.clientId, config.clientSecret);
17
+ const {
18
+ authorization_endpoint: authorizationURL,
19
+ token_endpoint: tokenURL,
20
+ userinfo_endpoint: userinfoURL,
21
+ // TODO: implement logout
22
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
23
+ end_session_endpoint: logoutURL
24
+ } = issuer.serverMetadata();
17
25
  const query = getQuery(event);
18
26
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
19
27
  if (!query.code) {
@@ -46,7 +54,7 @@ export function defineOAuthCognitoEventHandler({ config, onSuccess, onError }) {
46
54
  }
47
55
  const tokenType = tokens.token_type;
48
56
  const accessToken = tokens.access_token;
49
- const user = await $fetch(`https://${urlBase}/oauth2/userInfo`, {
57
+ const user = await $fetch(userinfoURL, {
50
58
  headers: {
51
59
  Authorization: `${tokenType} ${accessToken}`
52
60
  }
@@ -11,8 +11,8 @@ export function defineOAuthDropboxEventHandler({ config, onSuccess, onError }) {
11
11
  authorizationParams: {}
12
12
  });
13
13
  const query = getQuery(event);
14
- if (!config.clientId) {
15
- return handleMissingConfiguration(event, "dropbox", ["clientId"], onError);
14
+ if (!config.clientId || !config.clientSecret) {
15
+ return handleMissingConfiguration(event, "dropbox", ["clientId", "clientSecret"], onError);
16
16
  }
17
17
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
18
18
  if (!query.code) {
@@ -24,8 +24,8 @@ export function defineOAuthFacebookEventHandler({
24
24
  if (!onError) throw error;
25
25
  return onError(event, error);
26
26
  }
27
- if (!config.clientId) {
28
- return handleMissingConfiguration(event, "facebook", ["clientId"], onError);
27
+ if (!config.clientId || !config.clientSecret) {
28
+ return handleMissingConfiguration(event, "facebook", ["clientId", "clientSecret"], onError);
29
29
  }
30
30
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
31
31
  if (!query.code) {
@@ -16,8 +16,8 @@ export function defineOAuthGoogleEventHandler({
16
16
  authorizationParams: {}
17
17
  });
18
18
  const query = getQuery(event);
19
- if (!config.clientId) {
20
- return handleMissingConfiguration(event, "google", ["clientId"], onError);
19
+ if (!config.clientId || !config.clientSecret) {
20
+ return handleMissingConfiguration(event, "google", ["clientId", "clientSecret"], onError);
21
21
  }
22
22
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
23
23
  if (!query.code) {
@@ -0,0 +1,26 @@
1
+ import type { OAuthConfig } from '#auth-utils';
2
+ export interface OAuthHubspotConfig {
3
+ /**
4
+ * Hubspot OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_HUBSPOT_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * Hubspot OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_HUBSPOT_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * Hubspot OAuth Redirect URL
15
+ * @default process.env.NUXT_OAUTH_HUBSPOT_REDIRECT_URL
16
+ */
17
+ redirectURL?: string;
18
+ /**
19
+ * Hubspot OAuth Scope
20
+ * @default ['oauth']
21
+ * @see https://developers.hubspot.com/beta-docs/guides/apps/authentication/scopes
22
+ * @example ['accounting', 'automation', 'actions']
23
+ */
24
+ scope?: string[];
25
+ }
26
+ export declare function defineOAuthHubspotEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthHubspotConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -0,0 +1,57 @@
1
+ import { eventHandler, getQuery, sendRedirect } from "h3";
2
+ import { withQuery } from "ufo";
3
+ import defu from "defu";
4
+ import {
5
+ getOAuthRedirectURL,
6
+ handleAccessTokenErrorResponse,
7
+ handleMissingConfiguration,
8
+ requestAccessToken
9
+ } from "../utils.js";
10
+ import { useRuntimeConfig } from "#imports";
11
+ export function defineOAuthHubspotEventHandler({ config, onSuccess, onError }) {
12
+ return eventHandler(async (event) => {
13
+ config = defu(config, useRuntimeConfig(event).oauth?.hubspot);
14
+ if (!config.clientId || !config.clientSecret || !config.redirectURL) {
15
+ return handleMissingConfiguration(event, "hubspot", ["clientId", "clientSecret", "redirectURL"], onError);
16
+ }
17
+ const query = getQuery(event);
18
+ const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
19
+ if (query.error) {
20
+ return handleAccessTokenErrorResponse(event, "hubspot", query, onError);
21
+ }
22
+ if (!query.code) {
23
+ return sendRedirect(
24
+ event,
25
+ withQuery("https://app.hubspot.com/oauth/authorize", {
26
+ client_id: config.clientId,
27
+ redirect_uri: redirectURL,
28
+ scope: config.scope?.join(" ") || "oauth"
29
+ })
30
+ );
31
+ }
32
+ const tokens = await requestAccessToken(
33
+ "https://api.hubapi.com/oauth/v1/token",
34
+ {
35
+ body: {
36
+ client_id: config.clientId,
37
+ client_secret: config.clientSecret,
38
+ code: query.code,
39
+ redirect_uri: redirectURL,
40
+ grant_type: "authorization_code"
41
+ }
42
+ }
43
+ );
44
+ if (tokens.error) {
45
+ return handleAccessTokenErrorResponse(event, "hubspot", tokens, onError);
46
+ }
47
+ const info = await $fetch("https://api.hubapi.com/oauth/v1/access-tokens/" + tokens.access_token);
48
+ return onSuccess(event, {
49
+ user: {
50
+ id: info.user_id,
51
+ email: info.user,
52
+ domain: info.hub_domain
53
+ },
54
+ tokens
55
+ });
56
+ });
57
+ }
@@ -29,8 +29,8 @@ export function defineOAuthInstagramEventHandler({
29
29
  if (!onError) throw error;
30
30
  return onError(event, error);
31
31
  }
32
- if (!config.clientId) {
33
- return handleMissingConfiguration(event, "instagram", ["clientId"], onError);
32
+ if (!config.clientId || !config.clientSecret) {
33
+ return handleMissingConfiguration(event, "instagram", ["clientId", "clientSecret"], onError);
34
34
  }
35
35
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
36
36
  if (!query.code) {
@@ -12,10 +12,17 @@ export interface OAuthKeycloakConfig {
12
12
  clientSecret?: string;
13
13
  /**
14
14
  * Keycloak OAuth Server URL
15
- * @example http://192.168.1.10:8080/auth
15
+ * @example http://192.168.1.10:8080
16
16
  * @default process.env.NUXT_OAUTH_KEYCLOAK_SERVER_URL
17
17
  */
18
18
  serverUrl?: string;
19
+ /**
20
+ * Optional Keycloak OAuth Server URL to use internally, e.g. if Nuxt connects to a Docker hostname while the browser
21
+ * redirect goes to localhost
22
+ * @example http://keycloak:8080
23
+ * @default process.env.NUXT_OAUTH_KEYCLOAK_SERVER_URL_INTERNAL
24
+ */
25
+ serverUrlInternal?: string;
19
26
  /**
20
27
  * Keycloak OAuth Realm
21
28
  * @default process.env.NUXT_OAUTH_KEYCLOAK_REALM
@@ -33,7 +40,7 @@ export interface OAuthKeycloakConfig {
33
40
  */
34
41
  authorizationParams?: Record<string, string>;
35
42
  /**
36
- * Redirect URL to to allow overriding for situations like prod failing to determine public hostname
43
+ * Redirect URL to allow overriding for situations like prod failing to determine public hostname
37
44
  * @default process.env.NUXT_OAUTH_KEYCLOAK_REDIRECT_URL or current URL
38
45
  */
39
46
  redirectURL?: string;
@@ -26,8 +26,9 @@ export function defineOAuthKeycloakEventHandler({
26
26
  return handleMissingConfiguration(event, "keycloak", ["clientId", "clientSecret", "serverUrl", "realm"], onError);
27
27
  }
28
28
  const realmURL = `${config.serverUrl}/realms/${config.realm}`;
29
+ const realmURLInternal = `${config.serverUrlInternal || config.serverUrl}/realms/${config.realm}`;
29
30
  const authorizationURL = `${realmURL}/protocol/openid-connect/auth`;
30
- const tokenURL = `${realmURL}/protocol/openid-connect/token`;
31
+ const tokenURL = `${realmURLInternal}/protocol/openid-connect/token`;
31
32
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
32
33
  if (!query.code) {
33
34
  config.scope = config.scope || ["openid"];
@@ -12,8 +12,8 @@ export function defineOAuthPaypalEventHandler({ config, onSuccess, onError }) {
12
12
  authorizationParams: {}
13
13
  });
14
14
  const query = getQuery(event);
15
- if (!config.clientId) {
16
- return handleMissingConfiguration(event, "paypal", ["clientId"], onError);
15
+ if (!config.clientId || !config.clientSecret) {
16
+ return handleMissingConfiguration(event, "paypal", ["clientId", "clientSecret"], onError);
17
17
  }
18
18
  let paypalAPI = "api-m.paypal.com";
19
19
  if (config.sandbox) {
@@ -11,8 +11,8 @@ export function defineOAuthSeznamEventHandler({ config, onSuccess, onError }) {
11
11
  userURL: "https://login.szn.cz/api/v1/user"
12
12
  });
13
13
  const query = getQuery(event);
14
- if (!config.clientId) {
15
- return handleMissingConfiguration(event, "seznam", ["clientId"], onError);
14
+ if (!config.clientId || !config.clientSecret) {
15
+ return handleMissingConfiguration(event, "seznam", ["clientId", "clientSecret"], onError);
16
16
  }
17
17
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
18
18
  if (!query.code) {
@@ -11,8 +11,8 @@ export function defineOAuthTwitchEventHandler({ config, onSuccess, onError }) {
11
11
  authorizationParams: {}
12
12
  });
13
13
  const query = getQuery(event);
14
- if (!config.clientId) {
15
- return handleMissingConfiguration(event, "twitch", ["clientId"], onError);
14
+ if (!config.clientId || !config.clientSecret) {
15
+ return handleMissingConfiguration(event, "twitch", ["clientId", "clientSecret"], onError);
16
16
  }
17
17
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
18
18
  if (!query.code) {
@@ -25,8 +25,8 @@ export function defineOAuthXEventHandler({
25
25
  }
26
26
  });
27
27
  const query = getQuery(event);
28
- if (!config.clientId) {
29
- return handleMissingConfiguration(event, "x", ["clientId"], onError);
28
+ if (!config.clientId || !config.clientSecret) {
29
+ return handleMissingConfiguration(event, "x", ["clientId", "clientSecret"], onError);
30
30
  }
31
31
  const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
32
32
  if (!query.code) {
@@ -1,5 +1,5 @@
1
1
  import type { H3Event, H3Error } from 'h3';
2
- export type OAuthProvider = 'auth0' | 'authentik' | 'battledotnet' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'github' | 'gitlab' | 'google' | 'instagram' | 'keycloak' | 'linear' | 'linkedin' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | (string & {});
2
+ export type OAuthProvider = 'auth0' | 'authentik' | 'battledotnet' | 'cognito' | 'discord' | 'dropbox' | 'facebook' | 'github' | 'gitlab' | 'google' | 'hubspot' | 'instagram' | 'keycloak' | 'linear' | 'linkedin' | 'microsoft' | 'paypal' | 'polar' | 'spotify' | 'seznam' | 'steam' | 'strava' | 'tiktok' | 'twitch' | 'vk' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | (string & {});
3
3
  export type OnError = (event: H3Event, error: H3Error) => Promise<void> | void;
4
4
  export interface OAuthConfig<TConfig, TUser = any, TTokens = any> {
5
5
  config?: TConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-auth-utils",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
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@9.13.2",
11
+ "packageManager": "pnpm@9.15.0",
12
12
  "exports": {
13
13
  ".": {
14
14
  "types": "./dist/types.d.ts",
@@ -36,12 +36,13 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@adonisjs/hash": "^9.0.5",
39
- "@nuxt/kit": "^3.14.159",
39
+ "@nuxt/kit": "^3.14.1592",
40
40
  "defu": "^6.1.4",
41
41
  "h3": "^1.13.0",
42
42
  "hookable": "^5.5.3",
43
43
  "ofetch": "^1.4.1",
44
44
  "ohash": "^1.1.4",
45
+ "openid-client": "^6.1.7",
45
46
  "pathe": "^1.1.2",
46
47
  "scule": "^1.3.0",
47
48
  "uncrypto": "^0.1.3"
@@ -59,20 +60,20 @@
59
60
  }
60
61
  },
61
62
  "devDependencies": {
62
- "@iconify-json/simple-icons": "^1.2.11",
63
+ "@iconify-json/simple-icons": "^1.2.15",
63
64
  "@nuxt/devtools": "latest",
64
- "@nuxt/eslint-config": "^0.6.1",
65
+ "@nuxt/eslint-config": "^0.7.3",
65
66
  "@nuxt/module-builder": "^0.8.4",
66
- "@nuxt/schema": "^3.14.159",
67
- "@nuxt/test-utils": "^3.14.4",
68
- "@nuxt/ui": "^2.19.2",
69
- "@nuxt/ui-pro": "^1.5.0",
67
+ "@nuxt/schema": "^3.14.1592",
68
+ "@nuxt/test-utils": "^3.15.1",
69
+ "@nuxt/ui": "^2.20.0",
70
+ "@nuxt/ui-pro": "^1.6.0",
70
71
  "@simplewebauthn/types": "^11.0.0",
71
72
  "changelogen": "^0.5.7",
72
- "eslint": "^9.14.0",
73
- "nuxt": "^3.14.159",
73
+ "eslint": "^9.16.0",
74
+ "nuxt": "^3.14.1592",
74
75
  "typescript": "^5.6.3",
75
- "vitest": "^2.1.5",
76
+ "vitest": "^2.1.8",
76
77
  "vue-tsc": "^2.1.10"
77
78
  }
78
79
  }