nuxt-auth-utils 0.5.5 → 0.5.6

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
@@ -224,6 +224,7 @@ It can also be set using environment variables:
224
224
  - Seznam
225
225
  - Spotify
226
226
  - Steam
227
+ - Strava
227
228
  - TikTok
228
229
  - Twitch
229
230
  - VK
@@ -231,6 +232,7 @@ It can also be set using environment variables:
231
232
  - X (Twitter)
232
233
  - XSUAA
233
234
  - Yandex
235
+ - Zitadel
234
236
 
235
237
  You can add your favorite provider by creating a new file in [src/runtime/server/lib/oauth/](./src/runtime/server/lib/oauth/).
236
238
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.5.5",
4
+ "version": "0.5.6",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -249,6 +249,11 @@ const module = defineNuxtModule({
249
249
  clientSecret: "",
250
250
  redirectURL: ""
251
251
  });
252
+ runtimeConfig.oauth.strava = defu(runtimeConfig.oauth.strava, {
253
+ clientId: "",
254
+ clientSecret: "",
255
+ redirectURL: ""
256
+ });
252
257
  }
253
258
  });
254
259
 
@@ -12,21 +12,21 @@ export interface OAuthInstagramConfig {
12
12
  clientSecret?: string;
13
13
  /**
14
14
  * Instagram OAuth Scope
15
- * @default [ 'user_profile' ]
15
+ * @required [ 'business_basic' ]
16
16
  * @see https://developers.facebook.com/docs/instagram-basic-display-api/overview#permissions
17
- * @example [ 'user_profile', 'user_media' ],
17
+ * @example [ 'business_basic', 'business_manage_messages' ],
18
18
  */
19
- scope?: string[];
19
+ scope?: ('business_basic' | 'business_content_publish' | 'business_manage_comments' | 'business_manage_messages')[];
20
20
  /**
21
21
  * Instagram OAuth User Fields
22
22
  * @default [ 'id', 'username'],
23
23
  * @see https://developers.facebook.com/docs/instagram-basic-display-api/reference/user#fields
24
- * @example [ 'id', 'username', 'account_type', 'media_count' ],
24
+ * @example [ 'id', 'username', 'user_id', 'account_type', 'profile_picture_url' ],
25
25
  */
26
- fields?: string[];
26
+ fields?: ('id' | 'user_id' | 'username' | 'name' | 'account_type' | 'profile_picture_url' | 'followers_count' | 'follows_count' | 'media_count')[];
27
27
  /**
28
28
  * Instagram OAuth Authorization URL
29
- * @default 'https://api.instagram.com/oauth/authorize'
29
+ * @default 'https://www.instagram.com/oauth/authorize'
30
30
  */
31
31
  authorizationURL?: string;
32
32
  /**
@@ -10,8 +10,8 @@ export function defineOAuthInstagramEventHandler({
10
10
  }) {
11
11
  return eventHandler(async (event) => {
12
12
  config = defu(config, useRuntimeConfig(event).oauth?.instagram, {
13
- scope: ["user_profile"],
14
- authorizationURL: "https://api.instagram.com/oauth/authorize",
13
+ scope: ["business_basic"],
14
+ authorizationURL: "https://www.instagram.com/oauth/authorize",
15
15
  tokenURL: "https://api.instagram.com/oauth/access_token",
16
16
  authorizationParams: {}
17
17
  });
@@ -20,7 +20,11 @@ export function defineOAuthInstagramEventHandler({
20
20
  const error = createError({
21
21
  statusCode: 401,
22
22
  message: `Instagram login failed: ${query.error || "Unknown error"}`,
23
- data: query
23
+ data: {
24
+ error: query.error,
25
+ error_reason: query.error_reason,
26
+ error_description: query.error_description
27
+ }
24
28
  });
25
29
  if (!onError) throw error;
26
30
  return onError(event, error);
@@ -36,7 +40,7 @@ export function defineOAuthInstagramEventHandler({
36
40
  withQuery(config.authorizationURL, {
37
41
  client_id: config.clientId,
38
42
  redirect_uri: redirectURL,
39
- scope: config.scope.join(" "),
43
+ scope: config.scope.join(),
40
44
  response_type: "code"
41
45
  })
42
46
  );
@@ -55,9 +59,9 @@ export function defineOAuthInstagramEventHandler({
55
59
  }
56
60
  const accessToken = tokens.access_token;
57
61
  config.fields = config.fields || ["id", "username"];
58
- const fields = config.fields.join(",");
62
+ const fields = config.fields.join();
59
63
  const user = await $fetch(
60
- `https://graph.instagram.com/v20.0/me?fields=${fields}&access_token=${accessToken}`
64
+ `https://graph.instagram.com/v21.0/me?fields=${fields}&access_token=${accessToken}`
61
65
  );
62
66
  if (!user) {
63
67
  throw new Error("Instagram login failed: no user found");
@@ -92,4 +92,4 @@ export interface OAuthSeznamUser {
92
92
  */
93
93
  gender?: string | null;
94
94
  }
95
- export declare function defineOAUthSeznamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSeznamConfig, OAuthSeznamUser>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
95
+ export declare function defineOAuthSeznamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSeznamConfig, OAuthSeznamUser>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -3,9 +3,9 @@ import { eventHandler, getQuery, sendRedirect } from "h3";
3
3
  import { withQuery } from "ufo";
4
4
  import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleMissingConfiguration, requestAccessToken } from "../utils.js";
5
5
  import { useRuntimeConfig } from "#imports";
6
- export function defineOAUthSeznamEventHandler({ config, onSuccess, onError }) {
6
+ export function defineOAuthSeznamEventHandler({ config, onSuccess, onError }) {
7
7
  return eventHandler(async (event) => {
8
- config = defu(config, useRuntimeConfig(event).oauth?.google, {
8
+ config = defu(config, useRuntimeConfig(event).oauth?.seznam, {
9
9
  authorizationURL: "https://login.szn.cz/api/v1/oauth/auth",
10
10
  tokenURL: "https://login.szn.cz/api/v1/oauth/token",
11
11
  userURL: "https://login.szn.cz/api/v1/user"
@@ -0,0 +1,116 @@
1
+ import type { OAuthConfig } from '#auth-utils';
2
+ export interface OAuthStravaConfig {
3
+ /**
4
+ * Strava OAuth Client ID
5
+ * @default process.env.NUXT_OAUTH_STRAVA_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * Strava OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_STRAVA_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * Strava OAuth Scope
15
+ * @default []
16
+ * @see https://developers.strava.com/docs/authentication/ # Details About Requesting Access
17
+ * @example ['read', 'read_all', 'profile:read_all', 'profile:write', 'activity:read', 'activity:read_all', 'activity:write']
18
+ */
19
+ scope?: string[];
20
+ /**
21
+ * Redirect URL to allow overriding for situations like prod failing to determine public hostname
22
+ * @default process.env.NUXT_OAUTH_STRAVA_REDIRECT_URL or current URL
23
+ */
24
+ redirectURL?: string;
25
+ /**
26
+ * To show the authorization prompt to the user, 'force' will always show the prompt
27
+ * @default 'auto'
28
+ * @see https://developers.strava.com/docs/authentication/ # Details About Requesting Access
29
+ */
30
+ approvalPrompt?: 'auto' | 'force';
31
+ }
32
+ export interface OAuthStravaUser {
33
+ /**
34
+ * The unique identifier of the athlete
35
+ */
36
+ id: number;
37
+ /**
38
+ * The username of the athlete
39
+ */
40
+ username: string;
41
+ /**
42
+ * Resource state, indicates level of detail.
43
+ * - Meta (1): Basic information
44
+ * - Summary (2): Summary information
45
+ * - Detail (3): Detailed information
46
+ * @see https://developers.strava.com/docs/reference/#api-models-DetailedAthlete
47
+ */
48
+ resource_state: 1 | 2 | 3;
49
+ /**
50
+ * The athlete's first name
51
+ */
52
+ firstname: string;
53
+ /**
54
+ * The athlete's last name
55
+ */
56
+ lastname: string;
57
+ /**
58
+ * The athlete's bio
59
+ */
60
+ bio: string;
61
+ /**
62
+ * The athlete's city
63
+ */
64
+ city: string;
65
+ /**
66
+ * The athlete's state or geographical region
67
+ */
68
+ state: string;
69
+ /**
70
+ * The athlete's country
71
+ */
72
+ country: string;
73
+ /**
74
+ * The athlete's sex
75
+ */
76
+ sex: string;
77
+ /**
78
+ * Whether the athlete has any Summit subscription
79
+ * @see https://developers.strava.com/docs/reference/#api-models-DetailedAthlete
80
+ */
81
+ summit: boolean;
82
+ /**
83
+ * The time at which the athlete was created
84
+ */
85
+ created_at: Date;
86
+ /**
87
+ * The time at which the athlete was last updated
88
+ */
89
+ updated_at: Date;
90
+ /**
91
+ * The athlete's weight
92
+ */
93
+ weight: number;
94
+ /**
95
+ * URL to a 124x124 pixel profile picture
96
+ */
97
+ profile_medium: string;
98
+ /**
99
+ * URL to a 62x62 pixel profile picture
100
+ */
101
+ profile: string;
102
+ /**
103
+ * The athlete's timezone
104
+ */
105
+ timezone: string;
106
+ }
107
+ export interface OAuthStravaTokens {
108
+ token_type: 'Bearer';
109
+ expires_at: number;
110
+ expires_in: number;
111
+ access_token: string;
112
+ refresh_token: string;
113
+ athlete: OAuthStravaUser;
114
+ error?: string;
115
+ }
116
+ export declare function defineOAuthStravaEventHandler({ config, onSuccess, onError, }: OAuthConfig<OAuthStravaConfig, OAuthStravaUser>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;
@@ -0,0 +1,73 @@
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, createError } from "#imports";
11
+ export function defineOAuthStravaEventHandler({
12
+ config,
13
+ onSuccess,
14
+ onError
15
+ }) {
16
+ return eventHandler(async (event) => {
17
+ config = defu(config, useRuntimeConfig(event).oauth?.strava);
18
+ const query = getQuery(event);
19
+ if (query.error) {
20
+ const error = createError({
21
+ statusCode: 401,
22
+ message: `Strava login failed: ${query.error || "Unknown error"}`,
23
+ data: query
24
+ });
25
+ if (!onError) throw error;
26
+ return onError(event, error);
27
+ }
28
+ if (!config.clientId || !config.clientSecret) {
29
+ return handleMissingConfiguration(
30
+ event,
31
+ "strava",
32
+ ["clientId", "clientSecret"],
33
+ onError
34
+ );
35
+ }
36
+ const authorizationURL = "https://www.strava.com/oauth/authorize";
37
+ const tokenURL = "https://www.strava.com/oauth/token";
38
+ const redirectURL = config.redirectURL || getOAuthRedirectURL(event);
39
+ if (!query.code) {
40
+ return sendRedirect(
41
+ event,
42
+ withQuery(authorizationURL, {
43
+ client_id: config.clientId,
44
+ redirect_uri: redirectURL,
45
+ response_type: "code",
46
+ approval_prompt: config.approvalPrompt || "auto",
47
+ scope: config.scope
48
+ })
49
+ );
50
+ }
51
+ const tokens = await requestAccessToken(tokenURL, {
52
+ body: {
53
+ client_id: config.clientId,
54
+ client_secret: config.clientSecret,
55
+ code: query.code,
56
+ grant_type: "authorization_code",
57
+ redirect_uri: redirectURL
58
+ }
59
+ });
60
+ if (tokens.error) {
61
+ return handleAccessTokenErrorResponse(event, "strava", tokens, onError);
62
+ }
63
+ const user = await $fetch("https://www.strava.com/api/v3/athlete", {
64
+ headers: {
65
+ Authorization: `Bearer ${tokens.access_token}`
66
+ }
67
+ });
68
+ return onSuccess(event, {
69
+ user,
70
+ tokens
71
+ });
72
+ });
73
+ }
@@ -5,22 +5,27 @@ import type { OAuthConfig } from '#auth-utils';
5
5
  */
6
6
  export interface OAuthWorkOSConfig {
7
7
  /**
8
- * WorkOS OAuth Client ID
8
+ * WorkOS OAuth Client ID *required
9
9
  * @default process.env.NUXT_OAUTH_WORKOS_CLIENT_ID
10
10
  */
11
11
  clientId?: string;
12
12
  /**
13
- * WorkOS OAuth Client Secret (API Key)
13
+ * WorkOS OAuth Client Secret (API Key) *required
14
14
  * @default process.env.NUXT_OAUTH_WORKOS_CLIENT_SECRET
15
15
  */
16
16
  clientSecret?: string;
17
17
  /**
18
- * WorkOS OAuth Connection ID (Not required for WorkOS)
18
+ * WorkOS OAuth Organization ID *not required
19
+ * @default process.env.NUXT_OAUTH_WORKOS_ORGANIZATION_ID
20
+ */
21
+ organizationId?: string;
22
+ /**
23
+ * WorkOS OAuth Connection ID *not required
19
24
  * @default process.env.NUXT_OAUTH_WORKOS_CONNECTION_ID
20
25
  */
21
26
  connectionId?: string;
22
27
  /**
23
- * WorkOS OAuth screen hint
28
+ * WorkOS OAuth screen hint *not required
24
29
  * @default 'sign-in'
25
30
  */
26
31
  screenHint?: 'sign-in' | 'sign-up';
@@ -21,14 +21,13 @@ export function defineOAuthWorkOSEventHandler({ config, onSuccess, onError }) {
21
21
  response_type: "code",
22
22
  provider: "authkit",
23
23
  client_id: config.clientId,
24
- redirect_uri: redirectURL,
25
- connection_id: config.connectionId,
26
- screen_hint: config.screenHint
24
+ redirect_uri: redirectURL || void 0,
25
+ connection_id: config.connectionId || void 0,
26
+ screen_hint: config.screenHint || "sign-in",
27
+ organization_id: config.organizationId || void 0
27
28
  })
28
29
  );
29
30
  }
30
- const ip_address = getRequestIP(event);
31
- const user_agent = getRequestHeader(event, "user-agent");
32
31
  const authenticateResponse = await requestAccessToken("https://api.workos.com/user_management/authenticate", {
33
32
  headers: {
34
33
  "Content-Type": "application/json"
@@ -38,8 +37,8 @@ export function defineOAuthWorkOSEventHandler({ config, onSuccess, onError }) {
38
37
  client_id: config.clientId,
39
38
  client_secret: config.clientSecret,
40
39
  redirect_uri: redirectURL,
41
- ip_address,
42
- user_agent,
40
+ ip_address: getRequestIP(event),
41
+ user_agent: getRequestHeader(event, "user-agent"),
43
42
  code: query.code
44
43
  }
45
44
  });
@@ -59,7 +59,6 @@ export function defineOAuthZitadelEventHandler({ config, onSuccess, onError }) {
59
59
  Accept: "application/json"
60
60
  }
61
61
  });
62
- console.log("Zitadel user:", user);
63
62
  if (!user) {
64
63
  const error = createError({
65
64
  statusCode: 500,
@@ -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' | 'tiktok' | 'twitch' | 'vk' | 'workos' | 'x' | 'xsuaa' | 'yandex' | 'zitadel' | (string & {});
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 & {});
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.5",
3
+ "version": "0.5.6",
4
4
  "description": "Add Authentication to Nuxt applications with secured & sealed cookies sessions.",
5
5
  "repository": {
6
6
  "type": "git",