@sveltebase/auth 1.4.1 → 1.4.4
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 +38 -406
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,441 +1,73 @@
|
|
|
1
1
|
# @sveltebase/auth
|
|
2
2
|
|
|
3
|
-
A lightweight, Edge-native, DB-agnostic authentication library
|
|
3
|
+
A lightweight, Edge-native, DB-agnostic authentication library for Svelte 5 and SvelteKit. It integrates with `@sveltebase/sync` for WebSocket session verification.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Sync Authentication
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **DB-Agnostic Design**: Works out-of-the-box with D1 SQLite, Drizzle, Prisma, Postgres, or any other database of your choice.
|
|
9
|
-
- **Fast, Database-Free SSR**: Page renders decode the signed cookie instantly without database queries or heavy cryptographic signature validation on initial loads.
|
|
10
|
-
- **Svelte 5 Reactive Getters**: Hydrate client state with a reactive getter function (`() => data.user`) so that the UI reactively updates without writing `$effect` sync boilerplate in layouts.
|
|
11
|
-
- **WebSocket Channel Verification**: Offloads token verification and database checkups to Sveltebase Sync's WebSocket connection, verifying credentials in the background.
|
|
12
|
-
- **Automatic Offline Cache Wiping**: Automatically cleans up local IndexedDB database tables and terminates WebSocket connections on session expiry, account deletion, or user logout.
|
|
13
|
-
- **Web Crypto API Native**: Built on top of `globalThis.crypto.subtle` (zero NPM dependencies) to run at maximum speed in Edge runtimes like Cloudflare Workers.
|
|
7
|
+
Use `jwtCookieAuth()` anywhere the sync WebSocket is upgraded. In one-worker Cloudflare apps, that is both the SvelteKit route used by Vite dev and the Worker wrapper used by Wrangler/prod.
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
Browser (Client) ------------[ GET /dashboard ]------------> SvelteKit Server (SSR)
|
|
22
|
-
│
|
|
23
|
-
getUserFromCookie()
|
|
24
|
-
(Fast JSON base64-decode)
|
|
25
|
-
│
|
|
26
|
-
Browser (Client) <-----------[ HTML + page.data ]───────────────────┘
|
|
27
|
-
```
|
|
28
|
-
SSR is instant because no database queries or cryptographic signature verifications are performed during the page load.
|
|
29
|
-
|
|
30
|
-
### 2. WebSocket Background Verification
|
|
31
|
-
```
|
|
32
|
-
Browser (Client) ────────────[ Connect WebSocket ]───────────> Sync Engine (DO)
|
|
33
|
-
│ │
|
|
34
|
-
├───────────────[ Subscribe: "users" channel ]───────────────>┤
|
|
35
|
-
│ │
|
|
36
|
-
│ verifyJWT()
|
|
37
|
-
│ (Crypto verification)
|
|
38
|
-
│ │
|
|
39
|
-
│ verifyUser()
|
|
40
|
-
│ (Database check)
|
|
41
|
-
│ │
|
|
42
|
-
│<──────────────[ Subscription Authorized ]───────────────────┤ (Success)
|
|
43
|
-
│ │
|
|
44
|
-
│<──────────────[ Subscription Error ]────────────────────────┘ (Fail)
|
|
45
|
-
│
|
|
46
|
-
▼ (If failed)
|
|
47
|
-
auth.logout()
|
|
48
|
-
(Wipes IndexedDB & redirects)
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
## 1. Installation
|
|
54
|
-
|
|
55
|
-
Add the package to your SvelteKit project workspace:
|
|
56
|
-
```bash
|
|
57
|
-
bun add @sveltebase/auth
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## 2. Server Setup
|
|
63
|
-
|
|
64
|
-
Configure the server-side authentication manager:
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// src/lib/server/auth.ts
|
|
68
|
-
import { createServerAuth } from "@sveltebase/auth";
|
|
69
|
-
import { JWT_SECRET } from "$env/static/private";
|
|
70
|
-
|
|
71
|
-
export interface AppUser {
|
|
72
|
-
id: string;
|
|
73
|
-
email: string;
|
|
74
|
-
name: string;
|
|
75
|
-
token: string; // Embedded JWT signature
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export const auth = createServerAuth<AppUser>({
|
|
79
|
-
jwtSecret: JWT_SECRET,
|
|
80
|
-
cookieName: "sf_session",
|
|
81
|
-
cookieOptions: {
|
|
82
|
-
maxAge: 60 * 60 * 24 * 7, // 1 week
|
|
83
|
-
path: "/",
|
|
84
|
-
httpOnly: true,
|
|
85
|
-
secure: true,
|
|
86
|
-
sameSite: "lax"
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 3. SvelteKit Route Integration
|
|
94
|
-
|
|
95
|
-
### Server load (`src/routes/+layout.server.ts`)
|
|
96
|
-
Retrieve the user payload from the cookies during page render:
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
import { getUserFromCookie } from "@sveltebase/auth";
|
|
100
|
-
import type { AppUser } from "$lib/auth-client.js";
|
|
101
|
-
import type { LayoutServerLoad } from "./$types";
|
|
102
|
-
|
|
103
|
-
export const load: LayoutServerLoad = async ({ cookies }) => {
|
|
104
|
-
// Sub-millisecond unverified JSON decode
|
|
105
|
-
const user = getUserFromCookie<AppUser>(cookies);
|
|
106
|
-
return { user };
|
|
107
|
-
};
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Server endpoints (`src/routes/api/auth/login/+server.ts`)
|
|
111
|
-
Set the session cookie upon credentials verification:
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
import { auth } from "$lib/server/auth.js";
|
|
115
|
-
import { json } from "@sveltejs/kit";
|
|
116
|
-
|
|
117
|
-
export const POST = async ({ cookies, request }) => {
|
|
118
|
-
const credentials = await request.json();
|
|
119
|
-
|
|
120
|
-
// 1. Verify credentials with your database
|
|
121
|
-
const dbUser = await verifyCredentials(credentials);
|
|
122
|
-
if (!dbUser) {
|
|
123
|
-
return new Response("Invalid credentials", { status: 401 });
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// 2. setSession creates the JWT, embeds it in user.token, and writes the cookie
|
|
127
|
-
const sessionUser = await auth.login(cookies, {
|
|
128
|
-
id: dbUser.id,
|
|
129
|
-
email: dbUser.email,
|
|
130
|
-
name: dbUser.name
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
return json({ success: true, user: sessionUser });
|
|
134
|
-
};
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
## 4. Client Setup (Svelte 5)
|
|
140
|
-
|
|
141
|
-
Initialize the client auth state, linking it to your `@sveltebase/sync` client:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// src/lib/auth-client.ts
|
|
145
|
-
import { createAuth } from "@sveltebase/auth/client";
|
|
146
|
-
import { sync } from "./sync-client.js"; // your Sveltebase Sync instance
|
|
147
|
-
import type { AppUser } from "./server/auth.js";
|
|
9
|
+
```ts
|
|
10
|
+
// src/routes/api/sync/+server.ts
|
|
11
|
+
import { jwtCookieAuth } from "@sveltebase/auth/sync";
|
|
12
|
+
import { syncEngineRoute } from "@sveltebase/sync/sveltekit";
|
|
13
|
+
import { handlers } from "$lib/server/sync-handlers";
|
|
148
14
|
|
|
149
|
-
export const
|
|
150
|
-
|
|
15
|
+
export const { GET } = syncEngineRoute({
|
|
16
|
+
handlers,
|
|
17
|
+
auth: jwtCookieAuth(),
|
|
18
|
+
allowUnauthenticated: true,
|
|
151
19
|
});
|
|
152
20
|
```
|
|
153
21
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
```svelte
|
|
158
|
-
<script lang="ts">
|
|
159
|
-
import { auth } from "$lib/auth-client";
|
|
160
|
-
let { data, children } = $props();
|
|
161
|
-
|
|
162
|
-
// Initialize once. It automatically tracks changes to data.user
|
|
163
|
-
auth.init(() => data.user);
|
|
164
|
-
</script>
|
|
165
|
-
|
|
166
|
-
{@render children()}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## 5. Sync Worker Verification
|
|
172
|
-
|
|
173
|
-
Sync authentication is verified inside the standalone sync Worker, not in the SvelteKit app Worker. The app Worker should proxy `/api/sync` to the sync Worker and should not forward resolved auth objects.
|
|
174
|
-
|
|
175
|
-
Create the sync Worker with `jwtCookieAuth()`:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
// src/worker/sync.ts
|
|
22
|
+
```ts
|
|
23
|
+
// src/worker/app.ts
|
|
24
|
+
import app from "../../.svelte-kit/cloudflare/_worker.js";
|
|
179
25
|
import { jwtCookieAuth } from "@sveltebase/auth/sync";
|
|
180
|
-
import {
|
|
26
|
+
import { createSyncAppWorker, SyncEngine } from "@sveltebase/sync/cloudflare";
|
|
181
27
|
import { handlers } from "$lib/server/sync-handlers";
|
|
182
28
|
|
|
183
|
-
export default
|
|
29
|
+
export default createSyncAppWorker(app, {
|
|
184
30
|
handlers,
|
|
185
|
-
auth: jwtCookieAuth()
|
|
31
|
+
auth: jwtCookieAuth(),
|
|
32
|
+
allowUnauthenticated: true,
|
|
186
33
|
});
|
|
187
34
|
|
|
188
35
|
export { SyncEngine };
|
|
189
36
|
```
|
|
190
37
|
|
|
191
|
-
`jwtCookieAuth()` reads the `sf_session` cookie by default, verifies it with `platform.env.JWT_SECRET`, resolves identity from `user.id`, and
|
|
192
|
-
|
|
193
|
-
Both Workers need the same secret:
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
wrangler secret put JWT_SECRET --config wrangler.jsonc
|
|
197
|
-
wrangler secret put JWT_SECRET --config wrangler.sync.jsonc
|
|
198
|
-
```
|
|
38
|
+
`jwtCookieAuth()` reads the `sf_session` cookie by default, verifies it with `platform.env.JWT_SECRET`, resolves identity from `user.id`, and rejects unauthenticated WebSocket upgrades unless `allowUnauthenticated: true` is passed to the sync setup.
|
|
199
39
|
|
|
200
|
-
Register `createAuthSync()`
|
|
40
|
+
Register `createAuthSync()` in your sync handlers to protect the `users` channel and optionally check the database:
|
|
201
41
|
|
|
202
|
-
```
|
|
42
|
+
```ts
|
|
203
43
|
// src/lib/server/sync-handlers.ts
|
|
204
44
|
import { createAuthSync } from "@sveltebase/auth/server";
|
|
205
|
-
import {
|
|
45
|
+
import { eq } from "drizzle-orm";
|
|
46
|
+
import { getDB } from "./db";
|
|
47
|
+
import { users } from "./schema";
|
|
206
48
|
|
|
207
49
|
export const handlers = [
|
|
208
50
|
createAuthSync({
|
|
209
51
|
verifyUser: async (user, ctx) => {
|
|
210
52
|
const db = getDB(ctx.platform);
|
|
211
|
-
const activeUser = await db
|
|
53
|
+
const activeUser = await db
|
|
54
|
+
.select()
|
|
55
|
+
.from(users)
|
|
56
|
+
.where(eq(users.id, user.id))
|
|
57
|
+
.get();
|
|
212
58
|
return !!activeUser && !activeUser.isSuspended;
|
|
213
59
|
},
|
|
214
60
|
onUpdate: async (userId, changes, ctx) => {
|
|
215
61
|
const db = getDB(ctx.platform);
|
|
216
|
-
|
|
217
|
-
|
|
62
|
+
const [updated] = await db
|
|
63
|
+
.update(users)
|
|
64
|
+
.set(changes)
|
|
65
|
+
.where(eq(users.id, userId))
|
|
66
|
+
.returning();
|
|
67
|
+
return updated;
|
|
68
|
+
},
|
|
218
69
|
}),
|
|
219
|
-
todoSync
|
|
220
70
|
];
|
|
221
71
|
```
|
|
222
72
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
fetch: async (ctx) => {
|
|
227
|
-
const user = ctx.auth?.user;
|
|
228
|
-
if (!user) return [];
|
|
229
|
-
|
|
230
|
-
return db.select().from(todos).where(eq(todos.userId, user.id));
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Keep the browser connecting to the app origin so the session cookie is sent:
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
// src/routes/api/sync/+server.ts
|
|
238
|
-
import { SYNC_WORKER_URL } from "$env/static/private";
|
|
239
|
-
import { syncProxy } from "@sveltebase/sync/sveltekit";
|
|
240
|
-
|
|
241
|
-
export const { GET, POST } = syncProxy({
|
|
242
|
-
fallbackUrl: SYNC_WORKER_URL
|
|
243
|
-
});
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
## 6. API Reference
|
|
247
|
-
|
|
248
|
-
### Server APIs (`@sveltebase/auth`)
|
|
249
|
-
|
|
250
|
-
* **`createServerAuth<User>(config: AuthConfig)`**
|
|
251
|
-
Creates cookie management helpers.
|
|
252
|
-
* `login(cookies: Cookies, userPayload: Omit<User, 'token'>, options?): Promise<User>`: Encodes and writes session to cookie.
|
|
253
|
-
* `logout(cookies: Cookies, options?): void`: Deletes the session cookie.
|
|
254
|
-
* **`getUserFromCookie<User>(cookies: Cookies, cookieName?): User | null`**
|
|
255
|
-
Decodes the cookie payload without signature verification (fast SSR).
|
|
256
|
-
* **`getUserFromRequest<User>(request: Request, cookieName?): User | null`**
|
|
257
|
-
Parses raw cookie header on standard web requests (e.g. Workers, Durable Objects).
|
|
258
|
-
* **`getVerifiedUserFromRequest<User>(request: Request, jwtSecret: string, cookieName?): Promise<User | null>`**
|
|
259
|
-
Parses request cookies and cryptographically verifies the token signature.
|
|
260
|
-
|
|
261
|
-
### Client APIs (`@sveltebase/auth/client`)
|
|
262
|
-
|
|
263
|
-
* **`createAuth<User>(config: AuthClientConfig)`**
|
|
264
|
-
Creates the client reactive state.
|
|
265
|
-
* `get user(): User | null`: Returns the active user. Supports Svelte 5 reactive lookups.
|
|
266
|
-
* `set user(value: User | null)`: Overrides local user state (optimistic mutations).
|
|
267
|
-
* `isAuthenticated: boolean`: Helper check.
|
|
268
|
-
* `init(user: MaybeGetter<User | null>)`: Binds layout page data.
|
|
269
|
-
* `update(changes: Partial<User>): Promise<void>`: Optimistically updates user, syncs over WS, and rewrites the cookie.
|
|
270
|
-
* `logout(): Promise<void>`: Deletes session and clears IndexedDB cache.
|
|
271
|
-
|
|
272
|
-
### Sync Server Handler (`@sveltebase/auth/server`)
|
|
273
|
-
|
|
274
|
-
* **`createAuthSync(config: SyncAuthConfig)`**
|
|
275
|
-
Establishes the `"users"` sync channel. Use `jwtCookieAuth()` in the standalone sync Worker to populate `ctx.auth` and `ctx.identity` for all sync handlers.
|
|
276
|
-
* **`jwtCookieAuth(options?)`** from `@sveltebase/auth/sync`
|
|
277
|
-
Verifies the `sf_session` cookie using `platform.env.JWT_SECRET` during the sync Worker websocket handshake.
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
## 7. Google OAuth Integration
|
|
282
|
-
|
|
283
|
-
`@sveltebase/auth/google` provides a fully reactive Svelte 5 wrapper for the **Google Identity Services (GIS)** SDK. It allows you to embed official Google Sign-In buttons, use One Tap login, or trigger custom-styled login buttons.
|
|
284
|
-
|
|
285
|
-
### Wrapper Setup (`GoogleOAuthProvider`)
|
|
286
|
-
|
|
287
|
-
Wrap your page or layout where you intend to use Google Sign-In with the `<GoogleOAuthProvider>` and pass your Google Client ID:
|
|
288
|
-
|
|
289
|
-
```svelte
|
|
290
|
-
<script lang="ts">
|
|
291
|
-
import { GoogleOAuthProvider } from "@sveltebase/auth/google";
|
|
292
|
-
import MyLoginComponent from "./MyLoginComponent.svelte";
|
|
293
|
-
</script>
|
|
294
|
-
|
|
295
|
-
<GoogleOAuthProvider clientId="YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com">
|
|
296
|
-
<MyLoginComponent />
|
|
297
|
-
</GoogleOAuthProvider>
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Standard Sign-In Button (`GoogleLogin`)
|
|
301
|
-
|
|
302
|
-
The `<GoogleLogin>` component renders the official iframe-based customizable button:
|
|
303
|
-
|
|
304
|
-
```svelte
|
|
305
|
-
<!-- MyLoginComponent.svelte -->
|
|
306
|
-
<script lang="ts">
|
|
307
|
-
import { GoogleLogin } from "@sveltebase/auth/google";
|
|
308
|
-
import type { CredentialResponse } from "@sveltebase/auth/google";
|
|
309
|
-
|
|
310
|
-
function handleSuccess(response: CredentialResponse) {
|
|
311
|
-
console.log("JWT credential token:", response.credential);
|
|
312
|
-
// Send this credential to your backend to log in or create an account!
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function handleError() {
|
|
316
|
-
console.error("Sign-In failed");
|
|
317
|
-
}
|
|
318
|
-
</script>
|
|
319
|
-
|
|
320
|
-
<GoogleLogin onSuccess={handleSuccess} onError={handleError} />
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Custom Styled Buttons (`createGoogleLogin`)
|
|
324
|
-
|
|
325
|
-
For custom-styled login buttons, use the `createGoogleLogin` helper. It must be called in a child component of `<GoogleOAuthProvider>`. It returns a trigger `login` function alongside reactive `loading` and `error` states:
|
|
326
|
-
|
|
327
|
-
```svelte
|
|
328
|
-
<!-- MyLoginComponent.svelte -->
|
|
329
|
-
<script lang="ts">
|
|
330
|
-
import { createGoogleLogin } from "@sveltebase/auth/google";
|
|
331
|
-
|
|
332
|
-
const googleAuth = createGoogleLogin({
|
|
333
|
-
flow: "implicit", // or 'auth-code'
|
|
334
|
-
scope: "email profile", // additional scopes if needed
|
|
335
|
-
onSuccess: (response) => {
|
|
336
|
-
console.log("OAuth response:", response); // contains access_token or code
|
|
337
|
-
},
|
|
338
|
-
onError: (err) => {
|
|
339
|
-
console.error("Auth error:", err);
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
</script>
|
|
343
|
-
|
|
344
|
-
<button
|
|
345
|
-
onclick={() => googleAuth.login()}
|
|
346
|
-
disabled={googleAuth.loading}
|
|
347
|
-
class="custom-btn"
|
|
348
|
-
>
|
|
349
|
-
{#if googleAuth.loading}
|
|
350
|
-
Logging in...
|
|
351
|
-
{:else}
|
|
352
|
-
Login with Google (Custom UI)
|
|
353
|
-
{/if}
|
|
354
|
-
</button>
|
|
355
|
-
|
|
356
|
-
{#if googleAuth.error}
|
|
357
|
-
<p class="error">Error: {googleAuth.error.message}</p>
|
|
358
|
-
{/if}
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Google One Tap (`GoogleOneTapLogin`)
|
|
362
|
-
|
|
363
|
-
Mount the `<GoogleOneTapLogin>` component to display Google's native One Tap prompt when the page loads:
|
|
364
|
-
|
|
365
|
-
```svelte
|
|
366
|
-
<script lang="ts">
|
|
367
|
-
import { GoogleOneTapLogin } from "@sveltebase/auth/google";
|
|
368
|
-
import type { CredentialResponse } from "@sveltebase/auth/google";
|
|
369
|
-
</script>
|
|
370
|
-
|
|
371
|
-
<GoogleOneTapLogin
|
|
372
|
-
onSuccess={(response: CredentialResponse) => console.log("One Tap JWT:", response.credential)}
|
|
373
|
-
onError={() => console.error("One Tap dismissed/failed")}
|
|
374
|
-
/>
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Revoking/Logging Out (`googleLogout`)
|
|
378
|
-
|
|
379
|
-
To sign out the user from the current Google session and disable automatic sign-in on future visits:
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
import { googleLogout } from "@sveltebase/auth/google";
|
|
383
|
-
|
|
384
|
-
function logout() {
|
|
385
|
-
googleLogout();
|
|
386
|
-
// ... clear local user session state
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
### Decoding Credentials (`decodeCredentials`)
|
|
391
|
-
|
|
392
|
-
When using the `<GoogleLogin>` or `<GoogleOneTapLogin>` components, Google returns a credential string which is a signed JWT token containing the user's profile information. You can use the `decodeCredentials` function to decode this token on either the client or server into a typed `GoogleData` object:
|
|
393
|
-
|
|
394
|
-
```svelte
|
|
395
|
-
<script lang="ts">
|
|
396
|
-
import { GoogleLogin, decodeCredentials } from "@sveltebase/auth/google";
|
|
397
|
-
import type { CredentialResponse, GoogleData } from "@sveltebase/auth/google";
|
|
398
|
-
|
|
399
|
-
function handleSuccess(response: CredentialResponse) {
|
|
400
|
-
if (response.credential) {
|
|
401
|
-
const decoded: GoogleData = decodeCredentials(response.credential);
|
|
402
|
-
console.log("Decoded user profile:", decoded);
|
|
403
|
-
console.log("User email:", decoded.email);
|
|
404
|
-
console.log("User name:", decoded.name);
|
|
405
|
-
console.log("Profile picture:", decoded.picture);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
</script>
|
|
409
|
-
|
|
410
|
-
<GoogleLogin onSuccess={handleSuccess} />
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
### Cryptographically Verifying ID Tokens (`verifyIdToken`)
|
|
414
|
-
|
|
415
|
-
To securely verify the authenticity of a Google Identity credential (JWT) on your server (e.g. SvelteKit `+server.ts` or form actions), use `verifyIdToken`. It fetches Google's public JWK keys and cryptographically verifies the token's RS256 signature and standard claims using the Web Crypto API.
|
|
416
|
-
|
|
417
|
-
> [!IMPORTANT]
|
|
418
|
-
> This function **does not** require a Google Client Secret. It only requires your **Google Client ID** to verify the token's audience.
|
|
419
|
-
|
|
420
|
-
```typescript
|
|
421
|
-
import { verifyIdToken } from "@sveltebase/auth/google";
|
|
422
|
-
|
|
423
|
-
export const POST = async ({ request }) => {
|
|
424
|
-
const { credential } = await request.json();
|
|
425
|
-
|
|
426
|
-
try {
|
|
427
|
-
const payload = await verifyIdToken({
|
|
428
|
-
credential,
|
|
429
|
-
clientId: "YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com"
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
console.log("Verified user email:", payload.email);
|
|
433
|
-
console.log("Verified user name:", payload.name);
|
|
434
|
-
|
|
435
|
-
// Create session, log in the user, etc.
|
|
436
|
-
return new Response(JSON.stringify({ success: true, user: payload }));
|
|
437
|
-
} catch (err: any) {
|
|
438
|
-
return new Response(err.message, { status: 400 });
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
```
|
|
73
|
+
Use `wrangler secret put JWT_SECRET --config wrangler.jsonc` for Wrangler/prod. Use `.env` for Vite dev when using `@sveltejs/adapter-cloudflare` platform proxy.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltebase/auth",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,13 +37,14 @@
|
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"svelte": "^5.0.0",
|
|
40
|
-
"@sveltejs/kit": "^2.0.0"
|
|
40
|
+
"@sveltejs/kit": "^2.0.0",
|
|
41
|
+
"@sveltebase/sync": "1.4.4"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/google.accounts": "^0.0.14"
|
|
44
45
|
},
|
|
45
46
|
"scripts": {
|
|
46
|
-
"build": "svelte-package --input ./src --output ./dist",
|
|
47
|
+
"build": "svelte-package --input ./src --output ./dist --tsconfig ./tsconfig.package.json",
|
|
47
48
|
"check": "tsc --project tsconfig.json --noEmit",
|
|
48
49
|
"clean": "rm -rf dist"
|
|
49
50
|
}
|