@floatingpixels/supabase-nuxt 0.1.7 → 0.1.8
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 +27 -2
- package/dist/module.d.mts +15 -0
- package/dist/module.d.ts +15 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +7 -2
- package/dist/runtime/plugins/{auth-redirect.mjs → middleware-auth-redirect.mjs} +5 -15
- package/dist/runtime/plugins/middleware-auth.d.ts +2 -0
- package/dist/runtime/plugins/middleware-auth.mjs +14 -0
- package/dist/runtime/server/services/supabaseServerClient.mjs +2 -2
- package/dist/runtime/server/services/supabaseServiceRole.mjs +1 -1
- package/dist/runtime/types/index.d.ts +15 -0
- package/package.json +1 -1
- /package/dist/runtime/plugins/{auth-redirect.d.ts → middleware-auth-redirect.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ Once the authorization flow is triggered using the `auth` wrapper of the `useSup
|
|
|
158
158
|
|
|
159
159
|
### E-Mail Authentication
|
|
160
160
|
|
|
161
|
-
When using e-mail authentication, a confirmation e-mail is sent to new users, and an e-mail containing a magic link is sent to existing users. For those links to work with your application, you need to adjust the e-mail templates in your Supabase settings under `
|
|
161
|
+
When using e-mail authentication, a confirmation e-mail is sent to new users, and an e-mail containing a magic link is sent to existing users. For those links to work with your application, you need to adjust the e-mail templates in your Supabase settings under `Authentication -> Email Templates`. The generated links must contain a `token_hash` and `type` URL parameter, and point to the confirmation URL of your app, which is `/supabase/confirm` by default. In addition you can set the URL parameter `next` to determine the route users will be forwarded to in your app when authorization is successful. If `next` is omitted, it will route to `/`. An example template looks like this:
|
|
162
162
|
|
|
163
163
|
```html
|
|
164
164
|
<h2>Confirm your signup</h2>
|
|
@@ -171,7 +171,9 @@ When using e-mail authentication, a confirmation e-mail is sent to new users, an
|
|
|
171
171
|
</p>
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
The confirmation route on your server is provided by this module, so you don't need to implement it yourself. It's available at `/supabase/confirm`. It will automatically confirm the user and redirect to the `next` route.
|
|
174
|
+
The confirmation route on your server is provided by this module, so you don't need to implement it yourself. It's available at `/supabase/confirm`. It will automatically confirm the user and redirect to the `next` route.
|
|
175
|
+
|
|
176
|
+
If you want to customize the confirmation route, you can do so by creating a server route to handle the request, and point to it in your Supabase e-mail template. Your custom route will receive the `token_hash` and `type` URL parameters, and the `next` URL parameter if provided. You can use the `useSupabaseClient` composable to confirm the user and redirect to the `next` route:
|
|
175
177
|
|
|
176
178
|
> ⚠️ You can use the provided confirm route at `/supabase/confirm`, the implementation of a custom route is optional!
|
|
177
179
|
|
|
@@ -247,6 +249,29 @@ export default defineEventHandler(async event => {
|
|
|
247
249
|
|
|
248
250
|
If `redirect` is set to `true` in the module options, users will be automatically routed to the login page when they are not authenticated. If you want to allow access to "public" pages, you just need to add them in the `exclude` `redirect` option, and they will not redirect unauthenticated users.
|
|
249
251
|
|
|
252
|
+
### Error Handling
|
|
253
|
+
|
|
254
|
+
When an authentication error occurs, an exception is thrown. You can create an error page in the root of your app, to show an appropriate error message, clear the error and send the user to an appropriate route to continue. Here is an example for `error.vue`:
|
|
255
|
+
|
|
256
|
+
```vue
|
|
257
|
+
<script setup lang="ts">
|
|
258
|
+
import type { H3Error } from 'h3'
|
|
259
|
+
const { error } = defineProps<{
|
|
260
|
+
error: H3Error
|
|
261
|
+
}>()
|
|
262
|
+
|
|
263
|
+
const handleError = () => clearError({ redirect: '/' })
|
|
264
|
+
</script>
|
|
265
|
+
|
|
266
|
+
<template>
|
|
267
|
+
<div>
|
|
268
|
+
<h2>{{ error.statusCode }}</h2>
|
|
269
|
+
<p>{{ error.message }}</p>
|
|
270
|
+
<button @click="handleError">Clear errors</button>
|
|
271
|
+
</div>
|
|
272
|
+
</template>
|
|
273
|
+
```
|
|
274
|
+
|
|
250
275
|
## Composables
|
|
251
276
|
|
|
252
277
|
### useSupabaseClient
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { SupabaseClientOptions } from '@supabase/supabase-js';
|
|
3
|
+
import { CookieOptions } from 'nuxt/app';
|
|
2
4
|
|
|
5
|
+
declare module '@nuxt/schema' {
|
|
6
|
+
interface PublicRuntimeConfig {
|
|
7
|
+
supabase: {
|
|
8
|
+
url: string
|
|
9
|
+
key: string
|
|
10
|
+
redirect: boolean
|
|
11
|
+
redirectOptions: RedirectOptions
|
|
12
|
+
cookieName: string
|
|
13
|
+
cookieOptions: CookieOptions
|
|
14
|
+
clientOptions: SupabaseClientOptions<string>
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
3
18
|
interface ModuleOptions {
|
|
4
19
|
/**
|
|
5
20
|
* Supabase API URL
|
package/dist/module.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { SupabaseClientOptions } from '@supabase/supabase-js';
|
|
3
|
+
import { CookieOptions } from 'nuxt/app';
|
|
2
4
|
|
|
5
|
+
declare module '@nuxt/schema' {
|
|
6
|
+
interface PublicRuntimeConfig {
|
|
7
|
+
supabase: {
|
|
8
|
+
url: string
|
|
9
|
+
key: string
|
|
10
|
+
redirect: boolean
|
|
11
|
+
redirectOptions: RedirectOptions
|
|
12
|
+
cookieName: string
|
|
13
|
+
cookieOptions: CookieOptions
|
|
14
|
+
clientOptions: SupabaseClientOptions<string>
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
3
18
|
interface ModuleOptions {
|
|
4
19
|
/**
|
|
5
20
|
* Supabase API URL
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -33,9 +33,13 @@ const module = defineNuxtModule({
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
+
// hooks: {
|
|
37
|
+
// 'pages:routerOptions': options => {
|
|
38
|
+
// console.info(`Router options: ${options}`)
|
|
39
|
+
// },
|
|
40
|
+
// },
|
|
36
41
|
setup(options, nuxt) {
|
|
37
42
|
const { resolve } = createResolver(import.meta.url);
|
|
38
|
-
console.log("Module setup function");
|
|
39
43
|
if (!options.url) {
|
|
40
44
|
console.warn("Missing `SUPABASE_URL` in `.env`");
|
|
41
45
|
}
|
|
@@ -55,6 +59,7 @@ const module = defineNuxtModule({
|
|
|
55
59
|
});
|
|
56
60
|
addPlugin(resolve("./runtime/plugins/supabase.server"));
|
|
57
61
|
addPlugin(resolve("./runtime/plugins/supabase.client"));
|
|
62
|
+
addPlugin(resolve("./runtime/plugins/middleware-auth"));
|
|
58
63
|
nuxt.hook("imports:dirs", (dirs) => {
|
|
59
64
|
dirs.push(resolve("./runtime/composables"));
|
|
60
65
|
});
|
|
@@ -67,7 +72,7 @@ const module = defineNuxtModule({
|
|
|
67
72
|
handler: resolve("./runtime/server/auth/callback")
|
|
68
73
|
});
|
|
69
74
|
if (options.redirect) {
|
|
70
|
-
addPlugin(resolve("./runtime/plugins/auth-redirect"));
|
|
75
|
+
addPlugin(resolve("./runtime/plugins/middleware-auth-redirect"));
|
|
71
76
|
}
|
|
72
77
|
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
73
78
|
nitroConfig.alias = nitroConfig.alias || {};
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { useSupabaseUser } from "../composables/useSupabaseUser.mjs";
|
|
2
|
-
import {
|
|
3
|
-
defineNuxtPlugin,
|
|
4
|
-
addRouteMiddleware,
|
|
5
|
-
defineNuxtRouteMiddleware,
|
|
6
|
-
useRuntimeConfig,
|
|
7
|
-
navigateTo,
|
|
8
|
-
abortNavigation
|
|
9
|
-
} from "#imports";
|
|
2
|
+
import { defineNuxtPlugin, addRouteMiddleware, defineNuxtRouteMiddleware, useRuntimeConfig, navigateTo } from "#imports";
|
|
10
3
|
export default defineNuxtPlugin({
|
|
11
|
-
name: "auth-redirect",
|
|
4
|
+
name: "middleware-auth-redirect",
|
|
12
5
|
setup() {
|
|
13
6
|
addRouteMiddleware(
|
|
14
|
-
"global-auth",
|
|
7
|
+
"02-global-auth-redirect",
|
|
15
8
|
defineNuxtRouteMiddleware(async (to) => {
|
|
16
|
-
if (to.path === "/supabase/confirm")
|
|
17
|
-
abortNavigation();
|
|
18
9
|
const config = useRuntimeConfig().public.supabase;
|
|
19
10
|
const { login, exclude } = config.redirectOptions;
|
|
20
|
-
const isExcluded = [...exclude, login
|
|
11
|
+
const isExcluded = [...exclude || [], login ? login : "/login"]?.some((path) => {
|
|
21
12
|
const regex = new RegExp(`^${path.replace(/\*/g, ".*")}$`);
|
|
22
13
|
return regex.test(to.path);
|
|
23
14
|
});
|
|
@@ -25,8 +16,7 @@ export default defineNuxtPlugin({
|
|
|
25
16
|
return;
|
|
26
17
|
const user = await useSupabaseUser();
|
|
27
18
|
if (!user) {
|
|
28
|
-
|
|
29
|
-
return navigateTo("/login");
|
|
19
|
+
return navigateTo("/login");
|
|
30
20
|
}
|
|
31
21
|
}),
|
|
32
22
|
{ global: true }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineNuxtPlugin, addRouteMiddleware, defineNuxtRouteMiddleware, navigateTo } from "#imports";
|
|
2
|
+
export default defineNuxtPlugin({
|
|
3
|
+
name: "middleware-auth",
|
|
4
|
+
setup() {
|
|
5
|
+
addRouteMiddleware(
|
|
6
|
+
"01-global-auth",
|
|
7
|
+
defineNuxtRouteMiddleware(async (to) => {
|
|
8
|
+
if (to.path.startsWith("/supabase/"))
|
|
9
|
+
navigateTo("/");
|
|
10
|
+
}),
|
|
11
|
+
{ global: true }
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -4,7 +4,7 @@ import { useRuntimeConfig } from "#imports";
|
|
|
4
4
|
export const supabaseServerClient = async (event) => {
|
|
5
5
|
const {
|
|
6
6
|
supabase: { url, key, cookieOptions }
|
|
7
|
-
} = useRuntimeConfig(
|
|
7
|
+
} = useRuntimeConfig().public;
|
|
8
8
|
let supabaseClient = event.context._supabaseClient;
|
|
9
9
|
if (!supabaseClient) {
|
|
10
10
|
supabaseClient = createServerClient(url, key, {
|
|
@@ -13,7 +13,7 @@ export const supabaseServerClient = async (event) => {
|
|
|
13
13
|
return getCookie(event, name);
|
|
14
14
|
},
|
|
15
15
|
set(name, value) {
|
|
16
|
-
setCookie(event, name, value);
|
|
16
|
+
setCookie(event, name, value, cookieOptions);
|
|
17
17
|
},
|
|
18
18
|
remove(key2, options) {
|
|
19
19
|
setCookie(event, key2, "", { ...options, expires: 0 });
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import { SupabaseClientOptions } from '@supabase/supabase-js'
|
|
2
|
+
import { CookieOptions } from 'nuxt/app'
|
|
3
|
+
declare module '@nuxt/schema' {
|
|
4
|
+
interface PublicRuntimeConfig {
|
|
5
|
+
supabase: {
|
|
6
|
+
url: string
|
|
7
|
+
key: string
|
|
8
|
+
redirect: boolean
|
|
9
|
+
redirectOptions: RedirectOptions
|
|
10
|
+
cookieName: string
|
|
11
|
+
cookieOptions: CookieOptions
|
|
12
|
+
clientOptions: SupabaseClientOptions<string>
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
1
16
|
export interface ModuleOptions {
|
|
2
17
|
/**
|
|
3
18
|
* Supabase API URL
|
package/package.json
CHANGED
|
File without changes
|