Skip to content

Commit 82cf862

Browse files
authored
feat(auth): jwt signing keys (#531)
1 parent 83a20a9 commit 82cf862

File tree

15 files changed

+1065
-858
lines changed

15 files changed

+1065
-858
lines changed

demo/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Live demo: https://supabase-demo-gamma.vercel.app
66

77
- Frontend:
88
- [Nuxt 3](https://nuxt.com/) - The Vue Framework for Web Architects
9-
- [Nuxt UI Pro](https://ui.nuxt.com/) for components
9+
- [Nuxt UI](https://ui.nuxt.com/) for components
1010
- [TailwindCSS](https://tailwindcss.com/) for styling and layout.
1111
- [Supabase Module](https://github.com/nuxt-modules/supabase) for user management and supabase data client.
1212
- Backend:
@@ -72,9 +72,6 @@ pnpm dev
7272

7373
## Production
7474

75-
> [!WARNING]
76-
> This project uses [Nuxt UI Pro](https://ui.nuxt.com/pro), you need a license to deploy it in production. However, you can use it for free in development.
77-
7875
Build the application for production:
7976

8077
```bash

demo/app.config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ export default defineAppConfig({
1111
},
1212
},
1313
},
14-
},
15-
uiPro: {
1614
header: {
1715
slots: {
1816
root: 'border-none',

demo/assets/css/main.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
@import "tailwindcss";
2-
@import "@nuxt/ui-pro";
2+
@import "@nuxt/ui";
33

44
:root {
55
--ui-header-height: 40px;
66

77
--ui-container: 100%;
8-
}
8+
}

demo/nuxt.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// https://nuxt.com/docs/api/configuration/nuxt-config
22
export default defineNuxtConfig({
3-
modules: ['@nuxt/eslint', '@nuxt/ui-pro', '@nuxtjs/supabase'],
3+
modules: ['@nuxt/eslint', '@nuxt/ui', '@nuxtjs/supabase'],
44
devtools: { enabled: true },
55
css: ['~/assets/css/main.css'],
66
compatibilityDate: '2025-05-15',

docs/content/1.getting-started/1.introduction.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Add `SUPABASE_URL` and `SUPABASE_KEY` to the `.env`:
3131

3232
```bash [env]
3333
SUPABASE_URL="https://example.supabase.co"
34-
SUPABASE_KEY="<your_key>"
34+
SUPABASE_KEY="<your_publishable_key>"
3535
```
3636

3737
::tip
@@ -61,12 +61,30 @@ The unique Supabase URL which is supplied when you create a new project in your
6161
6262
Default: `process.env.SUPABASE_KEY`
6363
64-
Supabase 'anon key', used to bypass the Supabase API gateway and interact with your Supabase database making use of user JWT to apply RLS Policies.
64+
Supabase `publishable key`, used to verify and decode the JWT. Can bypass the Supabase API gateway and interact with your Supabase database applying RLS Policies.
6565
66-
### `serviceKey`
66+
::note{to="https://supabase.com/blog/jwt-signing-keys"}
67+
In `v1.x.x` and earlier, this was referring to the `anon key`. With the introduction of JWT signing keys, Supabase now needs a "publishable key" to decode the JWT and let you interact with your database.
68+
::
69+
70+
### `secretKey`
71+
72+
Default: `process.env.SUPABASE_SECRET_KEY`
73+
74+
Supabase `secret key`, has super admin rights and can bypass your Row Level Security.
75+
76+
::warning
77+
This key should be kept secret and never exposed to the client. Keep it in environment variables.
78+
::
79+
80+
### `serviceKey` :u-badge{label="Deprecated" color="warning"}
6781
6882
Default: `process.env.SUPABASE_SERVICE_KEY`
6983
84+
::warning{to="https://supabase.com/blog/jwt-signing-keys"}
85+
*Legacy API key* used before signing JWT keys were introduced. Use `secretKey` instead. This option will be removed in a future version.
86+
::
87+
7088
Supabase 'service role key', has super admin rights and can bypass your Row Level Security.
7189
7290
### `useSsrCookies`
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
title: Migration Guide
3+
description: Learn how to migrate @nuxtjs/supabase to take advantage of JWT signing keys support
4+
navigation:
5+
title: Migration
6+
---
7+
8+
This guide will help you migrate from `v1.x` to `v2.x`, which introduces support for Supabase's new JWT signing keys.
9+
10+
## 🔐 What are JWT Signing Keys?
11+
12+
Supabase has introduced a major security improvement by moving from symmetric to asymmetric JWT (JSON Web Token) signing. This change brings security and performance improvements in how your applications handle authentication.
13+
14+
### The Problem with Symmetric Keys
15+
16+
Previously, Supabase used a single shared secret key for both creating and verifying tokens. This meant your app had to constantly call `supabase.auth.getUser()` to check if sessions were valid, creating network delays calling the Supabase Auth server.
17+
18+
### The Solution with Asymmetric JWT Signing Keys
19+
The new system uses two separate keys:
20+
- A private key (kept secure by Supabase) for creating tokens.
21+
- A public key (safe to share in your application) for verifying them.
22+
23+
Your application can now verify user sessions locally without contacting Supabase servers, making it faster and more reliable. This new key is named as `publishable key` on Supabase.
24+
25+
### Key Benefits
26+
27+
This upgrade eliminates authentication bottlenecks, improves security, and makes your applications work better at the edge (no extra calls to the Supabase Auth server).
28+
29+
::note{to="https://supabase.com/blog/jwt-signing-keys"}
30+
Read the full technical explanation in the official Supabase blog post.
31+
::
32+
33+
## 🚨 Breaking changes
34+
35+
### 1. `useSupabaseUser` Type Changes
36+
37+
`useSupabaseUser` now returns **JWT claims** instead of the full **User object**.
38+
39+
- **Before (v1.x):** `useSupabaseUser` returned the full `User` object from [auth.getUser()](https://supabase.com/docs/reference/javascript/auth-getuser)
40+
- **After (v2.x):** `useSupabaseUser` returns `Claims` object from [auth.getClaims()](https://supabase.com/docs/reference/javascript/auth-getclaims) as a [JWT Payload](https://supabase.com/docs/guides/auth/jwts)
41+
42+
::code-group
43+
```json [auth.getUser() as .json]
44+
{
45+
id: "11111111-1111-1111-1111-111111111111",
46+
aud: "authenticated",
47+
role: "authenticated",
48+
49+
email_confirmed_at: "2024-01-01T00:00:00Z",
50+
phone: "",
51+
confirmed_at: "2024-01-01T00:00:00Z",
52+
last_sign_in_at: "2024-01-01T00:00:00Z",
53+
app_metadata: {},
54+
user_metadata: {},
55+
identities: []
56+
}
57+
```
58+
59+
```json [auth.getClaims().claims as .json]
60+
{
61+
session_id: "11111111-1111-1111-1111-111111111111",
62+
sub: "11111111-1111-1111-1111-111111111111",
63+
aud: "authenticated",
64+
role: "authenticated",
65+
66+
aal: "aal1",
67+
amr: [],
68+
exp: 1715769600,
69+
iat: 1715766000,
70+
is_anonymous: false,
71+
iss: "https://project-id.supabase.co/auth/v1",
72+
phone: "+13334445555",
73+
app_metadata: {},
74+
user_metadata: {},
75+
// identities is missing
76+
// last_sign_in_at is missing
77+
// confirmed_at is missing
78+
// email_confirmed_at is missing
79+
}
80+
```
81+
::
82+
83+
::tip
84+
If you need the full User object, you'll need to explicitly call `auth.getUser()` but if you only need basic info (email, role...) no changes are required.
85+
::
86+
87+
88+
### 2. Environment variables changes
89+
90+
**Remaining key****`SUPABASE_KEY`** is now storing the `publishable key` instead of the `anon key`
91+
92+
**New key****`SUPABASE_SECRET_KEY`** is now storing the `secret key` of your Supabase project
93+
94+
**Deprecated key****`SUPABASE_SERVICE_KEY`** was previously storing the `service_role key` but is now deprecated in favor of `SUPABASE_SECRET_KEY`
95+
96+
## 📋 Migration Steps
97+
98+
### 1. Types changes
99+
100+
The first thing you need to do is to ensure the `useSupabaseUser` changes do not affect your existing code.
101+
102+
::tip
103+
Once you've updated the types, you can already test your application and it should still work as expected.
104+
::
105+
106+
### 2. Environment variables changes
107+
108+
The **Good news** ☀️ is that everything will continue to work as-is with your existing `SUPABASE_KEY` (aka `anon key`).
109+
110+
Same for `SUPABASE_SERVICE_KEY`, if you're using it to bypass Row Level Security, you will face a deprecation warning but it will still work.
111+
112+
::warning{to="https://supabase.com/blog/jwt-signing-keys"}
113+
However, we highly recommend you to enable JWT signing keys in your Supabase project and use your publishable key as `SUPABASE_KEY` and your secret key as `SUPABASE_SECRET_KEY`.
114+
::
115+
116+
#### 2.a. Enable JWT Signing Keys in Supabase Dashboard
117+
118+
Before migrating your environment variables, you need to enable JWT signing keys and thus create your JWT and API keys in your Supabase project:
119+
120+
<iframe
121+
width="560"
122+
height="315"
123+
src="https://www.youtube.com/embed/rwnOal_xRtM"
124+
frameborder="0"
125+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
126+
allowfullscreen
127+
></iframe>
128+
129+
::tip
130+
**Watch this video tutorial** from **6:20 to 12:20** to understand how to enable JWT signing keys in your Supabase dashboard and get your new secret key.
131+
::
132+
133+
#### 2.b. Use your new keys in your `.env` file
134+
135+
```bash [.env]
136+
SUPABASE_KEY=<your_publishable_key>
137+
SUPABASE_SECRET_KEY=<your_secret_key>
138+
```

docs/content/3.services/2.serverSupabaseServiceRole.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This function is designed to work only in [server routes](https://nuxt.com/docs/
1414

1515
It works similary as the [serverSupabaseClient](/services/serversupabaseclient) but it provides a client with super admin rights that can bypass your [Row Level Security](https://supabase.com/docs/guides/auth/row-level-security).
1616

17-
> The client is initialized with the `SUPABASE_SERVICE_KEY` you must have in your `.env` file. Checkout the doc if you want to know more about [Supabase keys](https://supabase.com/docs/learn/auth-deep-dive/auth-deep-dive-jwts#jwts-in-supabase).
17+
> The client is initialized with the `SUPABASE_SECRET_KEY` (recommended) or `SUPABASE_SERVICE_KEY` (deprecated) you must have in your `.env` file. We recommend using the new JWT signing keys (`SUPABASE_SECRET_KEY`) as described in the [Supabase blog post](https://supabase.com/blog/jwt-signing-keys).
1818
1919
Define your server route and just import the `serverSupabaseServiceRole` from `#supabase/server`.
2020

docs/content/index.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ seo:
1010
---
1111
orientation: horizontal
1212
---
13-
:::prose-pre{filename="pages/login.vue"}
14-
```vue
13+
```vue [pages/login.vue]
1514
<script setup lang="ts">
1615
const supabase = useSupabaseClient()
1716
const email = ref('')
@@ -32,7 +31,6 @@ orientation: horizontal
3231
/>
3332
</template>
3433
```
35-
:::
3634

3735
#title
3836
[Nuxt]{.text-primary} Supabase
@@ -61,6 +59,11 @@ A supa simple wrapper around supabase-js to enable usage and integration within
6159
---
6260
Star on GitHub
6361
:::
62+
63+
#headline
64+
:::u-button{size="sm" to="/getting-started/migration" variant="outline"}
65+
Nuxt Supabase v2 →
66+
:::
6467
::
6568

6669
::u-page-section
@@ -125,10 +128,10 @@ Shipped with many features
125128
to: /getting-started/authentication
126129
---
127130
#title
128-
Authentication support
131+
Authentication support with JWT signing keys
129132

130133
#description
131-
Secure your applications with authentication support provided by Supabase.
134+
Secure your applications with authentication support provided by Supabase with JWT signing keys support.
132135
:::
133136

134137
:::u-page-feature

docs/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
},
99
"devDependencies": {
1010
"@nuxtjs/plausible": "2.0.1",
11-
"better-sqlite3": "^12.2.0",
12-
"docus": "^4.1.2"
11+
"better-sqlite3": "^12.4.1",
12+
"docus": "^5.0.0"
1313
},
14-
"packageManager": "pnpm@10.15.1"
14+
"packageManager": "pnpm@10.17.1"
1515
}

0 commit comments

Comments
 (0)