nuxt-auth-utils 0.0.25 → 0.2.0

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.
Files changed (48) hide show
  1. package/README.md +87 -8
  2. package/dist/module.json +2 -2
  3. package/dist/module.mjs +22 -24
  4. package/dist/runtime/app/components/AuthState.vue +17 -0
  5. package/dist/runtime/{composables → app/composables}/session.d.ts +4 -0
  6. package/dist/runtime/{composables/session.mjs → app/composables/session.js} +7 -0
  7. package/dist/runtime/app/plugins/session.client.js +8 -0
  8. package/dist/runtime/app/plugins/session.server.js +11 -0
  9. package/dist/runtime/server/api/{session.delete.mjs → session.delete.js} +1 -1
  10. package/dist/runtime/server/api/{session.get.mjs → session.get.js} +1 -1
  11. package/dist/runtime/server/lib/oauth/{auth0.mjs → auth0.js} +2 -3
  12. package/dist/runtime/server/lib/oauth/{battledotnet.mjs → battledotnet.js} +1 -2
  13. package/dist/runtime/server/lib/oauth/{cognito.mjs → cognito.js} +2 -3
  14. package/dist/runtime/server/lib/oauth/{discord.mjs → discord.js} +2 -3
  15. package/dist/runtime/server/lib/oauth/{facebook.mjs → facebook.js} +1 -2
  16. package/dist/runtime/server/lib/oauth/{github.mjs → github.js} +2 -3
  17. package/dist/runtime/server/lib/oauth/{google.mjs → google.js} +2 -3
  18. package/dist/runtime/server/lib/oauth/{keycloak.mjs → keycloak.js} +2 -3
  19. package/dist/runtime/server/lib/oauth/{linkedin.mjs → linkedin.js} +2 -3
  20. package/dist/runtime/server/lib/oauth/{microsoft.mjs → microsoft.js} +2 -3
  21. package/dist/runtime/server/lib/oauth/paypal.d.ts +47 -0
  22. package/dist/runtime/server/lib/oauth/paypal.js +104 -0
  23. package/dist/runtime/server/lib/oauth/{spotify.mjs → spotify.js} +2 -3
  24. package/dist/runtime/server/lib/oauth/steam.d.ts +15 -0
  25. package/dist/runtime/server/lib/oauth/steam.js +54 -0
  26. package/dist/runtime/server/lib/oauth/{twitch.mjs → twitch.js} +2 -3
  27. package/dist/runtime/server/lib/oauth/x.d.ts +41 -0
  28. package/dist/runtime/server/lib/oauth/x.js +98 -0
  29. package/dist/runtime/server/lib/oauth/xsuaa.d.ts +26 -0
  30. package/dist/runtime/server/lib/oauth/xsuaa.js +73 -0
  31. package/dist/runtime/server/utils/oauth.d.ts +20 -12
  32. package/dist/runtime/server/utils/oauth.js +34 -0
  33. package/dist/runtime/server/utils/session.d.ts +15 -3
  34. package/dist/runtime/types/index.d.ts +2 -2
  35. package/dist/runtime/types/oauth-config.js +0 -0
  36. package/dist/runtime/types/session.d.ts +19 -0
  37. package/dist/runtime/types/session.js +0 -0
  38. package/dist/types.d.mts +1 -0
  39. package/dist/types.d.ts +1 -0
  40. package/package.json +15 -14
  41. package/dist/runtime/plugins/session.server.d.ts +0 -2
  42. package/dist/runtime/plugins/session.server.mjs +0 -9
  43. package/dist/runtime/server/utils/oauth.mjs +0 -26
  44. /package/dist/runtime/{types/index.mjs → app/plugins/session.client.d.ts} +0 -0
  45. /package/dist/runtime/{types/oauth-config.mjs → app/plugins/session.server.d.ts} +0 -0
  46. /package/dist/runtime/server/plugins/{oauth.mjs → oauth.js} +0 -0
  47. /package/dist/runtime/server/utils/{session.mjs → session.js} +0 -0
  48. /package/dist/runtime/types/{session.mjs → index.js} +0 -0
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![License][license-src]][license-href]
6
6
  [![Nuxt][nuxt-src]][nuxt-href]
7
7
 
8
- Minimalist Authentication module for Nuxt exposing Vue composables and server utils.
8
+ Add Authentication to Nuxt applications with secured & sealed cookies sessions.
9
9
 
10
10
  - [Release Notes](/CHANGELOG.md)
11
11
  - [Demo](https://github.com/atinux/nuxt-todos-edge)
@@ -14,12 +14,20 @@ Minimalist Authentication module for Nuxt exposing Vue composables and server ut
14
14
 
15
15
  ## Features
16
16
 
17
- - Secured & sealed cookies sessions
18
- - [OAuth Providers](#supported-oauth-providers)
17
+ - [Hybrid Rendering](#hybrid-rendering) support (SSR / CSR / SWR / Prerendering)
18
+ - [15+ OAuth Providers](#supported-oauth-providers)
19
+ - [Vue composable](#vue-composable)
20
+ - [Server utils](#server-utils)
21
+ - [`<AuthState>` component](#authstate-component)
22
+ - [Extendable with hooks](#extend-session)
19
23
 
20
24
  ## Requirements
21
25
 
22
- This module only works with SSR (server-side rendering) enabled as it uses server API routes. You cannot use this module with `nuxt generate`.
26
+ This module only works with a Nuxt server running as it uses server API routes (`nuxt build`).
27
+
28
+ This means that you cannot use this module with `nuxt generate`.
29
+
30
+ You can anyway use [Hybrid Rendering](#hybrid-rendering) to pre-render pages of your application or disable server-side rendering completely.
23
31
 
24
32
  ## Quick Setup
25
33
 
@@ -40,7 +48,7 @@ Nuxt Auth Utils generates one for you when running Nuxt in development the first
40
48
 
41
49
  3. That's it! You can now add authentication to your Nuxt app ✨
42
50
 
43
- ## Vue Composables
51
+ ## Vue Composable
44
52
 
45
53
  Nuxt Auth Utils automatically adds some plugins to fetch the current user session to let you access it from your Vue components.
46
54
 
@@ -72,7 +80,7 @@ The following helpers are auto-imported in your `server/` directory.
72
80
 
73
81
  ```ts
74
82
  // Set a user session, note that this data is encrypted in the cookie but can be decrypted with an API call
75
- // Only store the data that allow you to recognize an user, but do not store sensitive data
83
+ // Only store the data that allow you to recognize a user, but do not store sensitive data
76
84
  // Merges new data with existing data using defu()
77
85
  await setUserSession(event, {
78
86
  user: {
@@ -118,7 +126,7 @@ All helpers are exposed from the `oauth` global variable and can be used in your
118
126
 
119
127
  The pattern is `oauth.<provider>EventHandler({ onSuccess, config?, onError? })`, example: `oauth.githubEventHandler`.
120
128
 
121
- The helper returns an event handler that automatically redirects to the provider authorization page and then call `onSuccess` or `onError` depending on the result.
129
+ The helper returns an event handler that automatically redirects to the provider authorization page and then calls `onSuccess` or `onError` depending on the result.
122
130
 
123
131
  The `config` can be defined directly from the `runtimeConfig` in your `nuxt.config.ts`:
124
132
 
@@ -152,8 +160,12 @@ It can also be set using environment variables:
152
160
  - Keycloak
153
161
  - LinkedIn
154
162
  - Microsoft
163
+ - PayPal
155
164
  - Spotify
165
+ - Steam
156
166
  - Twitch
167
+ - X (Twitter)
168
+ - XSUAA
157
169
 
158
170
  You can add your favorite provider by creating a new file in [src/runtime/server/lib/oauth/](./src/runtime/server/lib/oauth/).
159
171
 
@@ -186,7 +198,7 @@ Make sure to set the callback URL in your OAuth app settings as `<your-domain>/a
186
198
 
187
199
  ### Extend Session
188
200
 
189
- We leverage hooks to let you extend the session data with your own data or to log when the user clear its session.
201
+ We leverage hooks to let you extend the session data with your own data or log when the user clears the session.
190
202
 
191
203
  ```ts
192
204
  // server/plugins/session.ts
@@ -206,6 +218,69 @@ export default defineNitroPlugin(() => {
206
218
  })
207
219
  ```
208
220
 
221
+ ## Server-Side Rendering
222
+
223
+ You can make authenticated requests both from the client and the server. However, you must use `useRequestFetch()` to make authenticated requests during SSR if you are not using `useFetch()`
224
+
225
+ ```vue
226
+ <script setup lang="ts">
227
+ // When using useAsyncData
228
+ const { data } = await useAsyncData('team', () => useRequestFetch()('/api/protected-endpoint'))
229
+
230
+ // useFetch will automatically use useRequestFetch during SSR
231
+ const { data } = await useFetch('/api/protected-endpoint')
232
+ </script>
233
+ ```
234
+
235
+ > There's [an open issue](https://github.com/nuxt/nuxt/issues/24813) to include credentials in `$fetch` in Nuxt.
236
+
237
+ ## Hybrid Rendering
238
+
239
+ When using [Nuxt `routeRules`](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering) to prerender or cache your pages, Nuxt Auth Utils will not fetch the user session during prerendering but instead fetch it on the client-side (after hydration).
240
+
241
+ This is because the user session is stored in a secure cookie and cannot be accessed during prerendering.
242
+
243
+ **This means that you should not rely on the user session during prerendering.**
244
+
245
+ ### `<AuthState>` component
246
+
247
+ You can use the `<AuthState>` component to safely display auth-related data in your components without worrying about the rendering mode.
248
+
249
+ One common use case if the Login button in the header:
250
+
251
+ ```vue
252
+ <template>
253
+ <header>
254
+ <AuthState v-slot="{ loggedIn, clear }">
255
+ <button v-if="loggedIn" @click="clear">Logout</button>
256
+ <NuxtLink v-else to="/login">Login</NuxtLink>
257
+ </AuthState>
258
+ </header>
259
+ </template>
260
+ ```
261
+
262
+ If the page is cached or prerendered, nothing will be rendered until the user session is fetched on the client-side.
263
+
264
+ You can use the `placeholder` slot to show a placeholder on server-side and while the user session is being fetched on client-side for the prerendered pages:
265
+
266
+ ```vue
267
+ <template>
268
+ <header>
269
+ <AuthState>
270
+ <template #default="{ loggedIn, clear }">
271
+ <button v-if="loggedIn" @click="clear">Logout</button>
272
+ <NuxtLink v-else to="/login">Login</NuxtLink>
273
+ </template>
274
+ <template #placeholder>
275
+ <button disabled>Loading...</button>
276
+ </template>
277
+ </AuthState>
278
+ </header>
279
+ </template>
280
+ ```
281
+
282
+ If you are caching your routes with `routeRules`, please make sure to use [`nitro-nightly`](https://nitro.unjs.io/guide/nightly) or Nitro >= `2.10.0` to support the client-side fetching of the user session.
283
+
209
284
  ## Configuration
210
285
 
211
286
  We leverage `runtimeConfig.session` to give the defaults option to [h3 `useSession`](https://h3.unjs.io/examples/handle-session).
@@ -237,6 +312,10 @@ Our defaults are:
237
312
 
238
313
  Checkout the [`SessionConfig`](https://github.com/unjs/h3/blob/c04c458810e34eb15c1647e1369e7d7ef19f567d/src/utils/session.ts#L20) for all options.
239
314
 
315
+ ## More
316
+
317
+ - [nuxt-authorization](https://github.com/barbapapazes/nuxt-authorization): Authorization module for managing permissions inside a Nuxt app, compatible with `nuxt-auth-utils`
318
+
240
319
  ## Development
241
320
 
242
321
  ```bash
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "auth-utils",
3
3
  "configKey": "auth",
4
- "version": "0.0.25",
4
+ "version": "0.2.0",
5
5
  "builder": {
6
- "@nuxt/module-builder": "0.6.0",
6
+ "@nuxt/module-builder": "0.7.1",
7
7
  "unbuild": "2.0.0"
8
8
  }
9
9
  }
package/dist/module.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
- import { defineNuxtModule, createResolver, addImportsDir, addPlugin, addServerPlugin, addServerHandler } from '@nuxt/kit';
2
+ import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir, addPlugin, addServerPlugin, addServerImportsDir, addServerHandler } from '@nuxt/kit';
3
3
  import { join } from 'pathe';
4
4
  import { defu } from 'defu';
5
5
  import { randomUUID } from 'uncrypto';
@@ -14,30 +14,12 @@ const module = defineNuxtModule({
14
14
  async setup(options, nuxt) {
15
15
  const resolver = createResolver(import.meta.url);
16
16
  nuxt.options.alias["#auth-utils"] = resolver.resolve("./runtime/types/index");
17
- addImportsDir(resolver.resolve("./runtime/composables"));
18
- addPlugin(resolver.resolve("./runtime/plugins/session.server"));
19
- if (nuxt.options.nitro.imports !== false) {
20
- nuxt.options.nitro.imports = defu(nuxt.options.nitro.imports, {
21
- presets: [
22
- {
23
- from: resolver.resolve("./runtime/server/utils/oauth"),
24
- imports: ["oauth"]
25
- },
26
- {
27
- from: resolver.resolve("./runtime/server/utils/session"),
28
- imports: [
29
- "sessionHooks",
30
- "getUserSession",
31
- "setUserSession",
32
- "replaceUserSession",
33
- "clearUserSession",
34
- "requireUserSession"
35
- ]
36
- }
37
- ]
38
- });
39
- }
17
+ addComponentsDir({ path: resolver.resolve("./runtime/app/components") });
18
+ addImportsDir(resolver.resolve("./runtime/app/composables"));
19
+ addPlugin(resolver.resolve("./runtime/app/plugins/session.server"));
20
+ addPlugin(resolver.resolve("./runtime/app/plugins/session.client"));
40
21
  addServerPlugin(resolver.resolve("./runtime/server/plugins/oauth"));
22
+ addServerImportsDir(resolver.resolve("./runtime/server/utils"));
41
23
  addServerHandler({
42
24
  handler: resolver.resolve("./runtime/server/api/session.delete"),
43
25
  route: "/api/_auth/session",
@@ -124,6 +106,22 @@ const module = defineNuxtModule({
124
106
  clientId: "",
125
107
  clientSecret: ""
126
108
  });
109
+ runtimeConfig.oauth.paypal = defu(runtimeConfig.oauth.paypal, {
110
+ clientId: "",
111
+ clientSecret: ""
112
+ });
113
+ runtimeConfig.oauth.steam = defu(runtimeConfig.oauth.steam, {
114
+ apiKey: ""
115
+ });
116
+ runtimeConfig.oauth.x = defu(runtimeConfig.oauth.x, {
117
+ clientId: "",
118
+ clientSecret: ""
119
+ });
120
+ runtimeConfig.oauth.xsuaa = defu(runtimeConfig.oauth.xsuaa, {
121
+ clientId: "",
122
+ clientSecret: "",
123
+ domain: ""
124
+ });
127
125
  }
128
126
  });
129
127
 
@@ -0,0 +1,17 @@
1
+ <script setup>
2
+ import { useUserSession } from '#imports'
3
+
4
+ const userSession = useUserSession()
5
+ const { ready } = userSession
6
+ </script>
7
+
8
+ <template>
9
+ <slot
10
+ v-if="ready"
11
+ v-bind="userSession"
12
+ />
13
+ <slot
14
+ v-else
15
+ name="placeholder"
16
+ />
17
+ </template>
@@ -1,2 +1,6 @@
1
1
  import type { UserSessionComposable } from '#auth-utils';
2
+ /**
3
+ * Composable to get back the user session and utils around it.
4
+ * @see https://github.com/atinux/nuxt-auth-utils
5
+ */
2
6
  export declare function useUserSession(): UserSessionComposable;
@@ -1,8 +1,11 @@
1
1
  import { useState, computed, useRequestFetch } from "#imports";
2
2
  const useSessionState = () => useState("nuxt-session", () => ({}));
3
+ const useAuthReadyState = () => useState("nuxt-auth-ready", () => false);
3
4
  export function useUserSession() {
4
5
  const sessionState = useSessionState();
6
+ const authReadyState = useAuthReadyState();
5
7
  return {
8
+ ready: computed(() => authReadyState.value),
6
9
  loggedIn: computed(() => Boolean(sessionState.value.user)),
7
10
  user: computed(() => sessionState.value.user || null),
8
11
  session: sessionState,
@@ -11,12 +14,16 @@ export function useUserSession() {
11
14
  };
12
15
  }
13
16
  async function fetch() {
17
+ const authReadyState = useAuthReadyState();
14
18
  useSessionState().value = await useRequestFetch()("/api/_auth/session", {
15
19
  headers: {
16
20
  Accept: "text/json"
17
21
  },
18
22
  retry: false
19
23
  }).catch(() => ({}));
24
+ if (!authReadyState.value) {
25
+ authReadyState.value = true;
26
+ }
20
27
  }
21
28
  async function clear() {
22
29
  await $fetch("/api/_auth/session", { method: "DELETE" });
@@ -0,0 +1,8 @@
1
+ import { defineNuxtPlugin, useUserSession } from "#imports";
2
+ export default defineNuxtPlugin(async (nuxtApp) => {
3
+ if (!nuxtApp.payload.serverRendered || Boolean(nuxtApp.payload.prerenderedAt) || Boolean(nuxtApp.payload.isCached)) {
4
+ nuxtApp.hook("app:mounted", async () => {
5
+ await useUserSession().fetch();
6
+ });
7
+ }
8
+ });
@@ -0,0 +1,11 @@
1
+ import { defineNuxtPlugin, useRequestEvent, useUserSession } from "#imports";
2
+ export default defineNuxtPlugin({
3
+ name: "session-fetch-plugin",
4
+ enforce: "pre",
5
+ async setup(nuxtApp) {
6
+ nuxtApp.payload.isCached = Boolean(useRequestEvent()?.context.cache);
7
+ if (nuxtApp.payload.serverRendered && !nuxtApp.payload.prerenderedAt && !nuxtApp.payload.isCached) {
8
+ await useUserSession().fetch();
9
+ }
10
+ }
11
+ });
@@ -1,5 +1,5 @@
1
1
  import { eventHandler } from "h3";
2
- import { clearUserSession } from "../utils/session.mjs";
2
+ import { clearUserSession } from "../utils/session.js";
3
3
  export default eventHandler(async (event) => {
4
4
  await clearUserSession(event);
5
5
  return { loggedOut: true };
@@ -1,5 +1,5 @@
1
1
  import { eventHandler } from "h3";
2
- import { requireUserSession, sessionHooks } from "../utils/session.mjs";
2
+ import { requireUserSession, sessionHooks } from "../utils/session.js";
3
3
  export default eventHandler(async (event) => {
4
4
  const session = await requireUserSession(event);
5
5
  await sessionHooks.callHookParallel("fetch", session, event);
@@ -1,6 +1,5 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
- import { ofetch } from "ofetch";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
6
5
  export function auth0EventHandler({ config, onSuccess, onError }) {
@@ -40,7 +39,7 @@ export function auth0EventHandler({ config, onSuccess, onError }) {
40
39
  })
41
40
  );
42
41
  }
43
- const tokens = await ofetch(
42
+ const tokens = await $fetch(
44
43
  tokenURL,
45
44
  {
46
45
  method: "POST",
@@ -70,7 +69,7 @@ export function auth0EventHandler({ config, onSuccess, onError }) {
70
69
  }
71
70
  const tokenType = tokens.token_type;
72
71
  const accessToken = tokens.access_token;
73
- const user = await ofetch(`https://${config.domain}/userinfo`, {
72
+ const user = await $fetch(`https://${config.domain}/userinfo`, {
74
73
  headers: {
75
74
  Authorization: `${tokenType} ${accessToken}`
76
75
  }
@@ -1,6 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
3
- import { ofetch } from "ofetch";
4
3
  import { withQuery, parsePath } from "ufo";
5
4
  import { defu } from "defu";
6
5
  import { useRuntimeConfig } from "#imports";
@@ -88,7 +87,7 @@ export function battledotnetEventHandler({ config, onSuccess, onError }) {
88
87
  return onError(event, error);
89
88
  }
90
89
  const accessToken = tokens.access_token;
91
- const user = await ofetch("https://oauth.battle.net/userinfo", {
90
+ const user = await $fetch("https://oauth.battle.net/userinfo", {
92
91
  headers: {
93
92
  "User-Agent": `Battledotnet-OAuth-${config.clientId}`,
94
93
  "Authorization": `Bearer ${accessToken}`
@@ -1,6 +1,5 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
- import { ofetch } from "ofetch";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
6
5
  export function cognitoEventHandler({ config, onSuccess, onError }) {
@@ -34,7 +33,7 @@ export function cognitoEventHandler({ config, onSuccess, onError }) {
34
33
  })
35
34
  );
36
35
  }
37
- const tokens = await ofetch(
36
+ const tokens = await $fetch(
38
37
  tokenURL,
39
38
  {
40
39
  method: "POST",
@@ -58,7 +57,7 @@ export function cognitoEventHandler({ config, onSuccess, onError }) {
58
57
  }
59
58
  const tokenType = tokens.token_type;
60
59
  const accessToken = tokens.access_token;
61
- const user = await ofetch(`https://${config.userPoolId}.auth.${config.region}.amazoncognito.com/oauth2/userInfo`, {
60
+ const user = await $fetch(`https://${config.userPoolId}.auth.${config.region}.amazoncognito.com/oauth2/userInfo`, {
62
61
  headers: {
63
62
  Authorization: `${tokenType} ${accessToken}`
64
63
  }
@@ -1,6 +1,5 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parseURL, stringifyParsedURL } from "ufo";
3
- import { ofetch } from "ofetch";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
6
5
  export function discordEventHandler({ config, onSuccess, onError }) {
@@ -43,7 +42,7 @@ export function discordEventHandler({ config, onSuccess, onError }) {
43
42
  }
44
43
  const parsedRedirectUrl = parseURL(redirectUrl);
45
44
  parsedRedirectUrl.search = "";
46
- const tokens = await ofetch(
45
+ const tokens = await $fetch(
47
46
  config.tokenURL,
48
47
  {
49
48
  method: "POST",
@@ -72,7 +71,7 @@ export function discordEventHandler({ config, onSuccess, onError }) {
72
71
  return onError(event, error);
73
72
  }
74
73
  const accessToken = tokens.access_token;
75
- const user = await ofetch("https://discord.com/api/users/@me", {
74
+ const user = await $fetch("https://discord.com/api/users/@me", {
76
75
  headers: {
77
76
  "user-agent": "Nuxt Auth Utils",
78
77
  "Authorization": `Bearer ${accessToken}`
@@ -5,7 +5,6 @@ import {
5
5
  getRequestURL,
6
6
  sendRedirect
7
7
  } from "h3";
8
- import { ofetch } from "ofetch";
9
8
  import { withQuery } from "ufo";
10
9
  import { defu } from "defu";
11
10
  import { useRuntimeConfig } from "#imports";
@@ -74,7 +73,7 @@ export function facebookEventHandler({
74
73
  const accessToken = tokens.access_token;
75
74
  config.fields = config.fields || ["id", "name"];
76
75
  const fields = config.fields.join(",");
77
- const user = await ofetch(
76
+ const user = await $fetch(
78
77
  `https://graph.facebook.com/v19.0/me?fields=${fields}&access_token=${accessToken}`
79
78
  );
80
79
  if (!user) {
@@ -1,5 +1,4 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
- import { ofetch } from "ofetch";
3
2
  import { withQuery } from "ufo";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
@@ -68,14 +67,14 @@ export function githubEventHandler({ config, onSuccess, onError }) {
68
67
  return onError(event, error);
69
68
  }
70
69
  const accessToken = tokens.access_token;
71
- const user = await ofetch("https://api.github.com/user", {
70
+ const user = await $fetch("https://api.github.com/user", {
72
71
  headers: {
73
72
  "User-Agent": `Github-OAuth-${config.clientId}`,
74
73
  "Authorization": `token ${accessToken}`
75
74
  }
76
75
  });
77
76
  if (!user.email && config.emailRequired) {
78
- const emails = await ofetch("https://api.github.com/user/emails", {
77
+ const emails = await $fetch("https://api.github.com/user/emails", {
79
78
  headers: {
80
79
  "User-Agent": `Github-OAuth-${config.clientId}`,
81
80
  "Authorization": `token ${accessToken}`
@@ -6,7 +6,6 @@ import {
6
6
  sendRedirect
7
7
  } from "h3";
8
8
  import { withQuery, parsePath } from "ufo";
9
- import { ofetch } from "ofetch";
10
9
  import { defu } from "defu";
11
10
  import { useRuntimeConfig } from "#imports";
12
11
  export function googleEventHandler({
@@ -52,7 +51,7 @@ export function googleEventHandler({
52
51
  client_secret: config.clientSecret,
53
52
  code
54
53
  };
55
- const tokens = await ofetch(config.tokenURL, {
54
+ const tokens = await $fetch(config.tokenURL, {
56
55
  method: "POST",
57
56
  body
58
57
  }).catch((error) => {
@@ -69,7 +68,7 @@ export function googleEventHandler({
69
68
  return onError(event, error);
70
69
  }
71
70
  const accessToken = tokens.access_token;
72
- const user = await ofetch(
71
+ const user = await $fetch(
73
72
  config.userURL,
74
73
  {
75
74
  headers: {
@@ -5,7 +5,6 @@ import {
5
5
  getRequestURL,
6
6
  sendRedirect
7
7
  } from "h3";
8
- import { ofetch } from "ofetch";
9
8
  import { withQuery, parsePath } from "ufo";
10
9
  import { defu } from "defu";
11
10
  import { useRuntimeConfig } from "#imports";
@@ -60,7 +59,7 @@ export function keycloakEventHandler({
60
59
  if (!config.scope.includes("openid")) {
61
60
  config.scope.push("openid");
62
61
  }
63
- const tokens = await ofetch(tokenURL, {
62
+ const tokens = await $fetch(tokenURL, {
64
63
  method: "POST",
65
64
  headers: {
66
65
  "Content-Type": "application/x-www-form-urlencoded"
@@ -86,7 +85,7 @@ export function keycloakEventHandler({
86
85
  return onError(event, error);
87
86
  }
88
87
  const accessToken = tokens.access_token;
89
- const user = await ofetch(
88
+ const user = await $fetch(
90
89
  `${realmURL}/protocol/openid-connect/userinfo`,
91
90
  {
92
91
  headers: {
@@ -1,6 +1,5 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parseURL, stringifyParsedURL } from "ufo";
3
- import { ofetch } from "ofetch";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
6
5
  export function linkedinEventHandler({ config, onSuccess, onError }) {
@@ -42,7 +41,7 @@ export function linkedinEventHandler({ config, onSuccess, onError }) {
42
41
  }
43
42
  const parsedRedirectUrl = parseURL(redirectUrl);
44
43
  parsedRedirectUrl.search = "";
45
- const tokens = await ofetch(
44
+ const tokens = await $fetch(
46
45
  config.tokenURL,
47
46
  {
48
47
  method: "POST",
@@ -71,7 +70,7 @@ export function linkedinEventHandler({ config, onSuccess, onError }) {
71
70
  return onError(event, error);
72
71
  }
73
72
  const accessToken = tokens.access_token;
74
- const user = await ofetch("https://api.linkedin.com/v2/userinfo", {
73
+ const user = await $fetch("https://api.linkedin.com/v2/userinfo", {
75
74
  headers: {
76
75
  "user-agent": "Nuxt Auth Utils",
77
76
  "Authorization": `Bearer ${accessToken}`
@@ -1,6 +1,5 @@
1
1
  import { eventHandler, createError, getQuery, getRequestURL, sendRedirect } from "h3";
2
2
  import { withQuery, parsePath } from "ufo";
3
- import { ofetch } from "ofetch";
4
3
  import { defu } from "defu";
5
4
  import { useRuntimeConfig } from "#imports";
6
5
  export function microsoftEventHandler({ config, onSuccess, onError }) {
@@ -40,7 +39,7 @@ export function microsoftEventHandler({ config, onSuccess, onError }) {
40
39
  data.append("client_secret", config.clientSecret);
41
40
  data.append("redirect_uri", parsePath(redirectUrl).pathname);
42
41
  data.append("code", String(code));
43
- const tokens = await ofetch(
42
+ const tokens = await $fetch(
44
43
  tokenURL,
45
44
  {
46
45
  method: "POST",
@@ -65,7 +64,7 @@ export function microsoftEventHandler({ config, onSuccess, onError }) {
65
64
  const tokenType = tokens.token_type;
66
65
  const accessToken = tokens.access_token;
67
66
  const userURL = config.userURL || "https://graph.microsoft.com/v1.0/me";
68
- const user = await ofetch(userURL, {
67
+ const user = await $fetch(userURL, {
69
68
  headers: {
70
69
  Authorization: `${tokenType} ${accessToken}`
71
70
  }
@@ -0,0 +1,47 @@
1
+ import type { OAuthConfig } from '#auth-utils';
2
+ export interface OAuthPaypalConfig {
3
+ /**
4
+ * PayPal Client ID
5
+ * @default process.env.NUXT_OAUTH_PAYPAL_CLIENT_ID
6
+ */
7
+ clientId?: string;
8
+ /**
9
+ * PayPal OAuth Client Secret
10
+ * @default process.env.NUXT_OAUTH_PAYPAL_CLIENT_SECRET
11
+ */
12
+ clientSecret?: string;
13
+ /**
14
+ * PayPal OAuth Scope
15
+ * @default []
16
+ * @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/reference/#scope-attributes
17
+ * @example ['email', 'profile']
18
+ */
19
+ scope?: string[];
20
+ /**
21
+ * Require email from user, adds the ['email'] scope if not present
22
+ * @default false
23
+ */
24
+ emailRequired?: boolean;
25
+ /**
26
+ * Use PayPal sandbox environment
27
+ * @default import.meta.dev // true in development, false in production
28
+ */
29
+ sandbox?: boolean;
30
+ /**
31
+ * PayPal OAuth Authorization URL
32
+ * @default 'https://www.paypal.com/signin/authorize'
33
+ */
34
+ authorizationURL?: string;
35
+ /**
36
+ * PayPal OAuth Token URL
37
+ * @default 'https://api-m.paypal.com/v1/oauth2/token'
38
+ */
39
+ tokenURL?: string;
40
+ /**
41
+ * Extra authorization parameters to provide to the authorization URL
42
+ * @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/build-button/#link-constructauthorizationendpoint
43
+ * @example { flowEntry: 'static' }
44
+ */
45
+ authorizationParams?: Record<string, string>;
46
+ }
47
+ export declare function paypalEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthPaypalConfig>): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void>>;