Statusphere, but in atcute and SvelteKit
atproto
svelte
sveltekit
drizzle
atcute
typescript
1import { error } from '@sveltejs/kit';
2
3import { Client } from '@atcute/client';
4import type { Did } from '@atcute/lexicons';
5import { isDid } from '@atcute/lexicons/syntax';
6import {
7 AuthMethodUnsatisfiableError,
8 TokenInvalidError,
9 TokenRefreshError,
10 TokenRevokedError,
11} from '@atcute/oauth-node-client';
12
13import { getRequestEvent } from '$app/server';
14
15import { getSignedCookie } from '$lib/server/auth/signed-cookie';
16import { oauth } from '$lib/server/oauth';
17
18export const SESSION_COOKIE = 'statusphere_session';
19
20export interface Session {
21 did: Did;
22}
23
24export interface AuthContext {
25 session: Session;
26 client: Client;
27}
28
29const isSessionInvalidError = (err: unknown): boolean => {
30 return (
31 err instanceof TokenRefreshError ||
32 err instanceof TokenInvalidError ||
33 err instanceof TokenRevokedError ||
34 err instanceof AuthMethodUnsatisfiableError
35 );
36};
37
38/**
39 * requires an authenticated session, throwing if not signed in or session is invalid.
40 * caches the result in locals for successive calls within the same request.
41 * @returns authenticated session and client
42 * @throws if not signed in or OAuth session is invalid
43 */
44export const requireAuth = async (): Promise<AuthContext> => {
45 const { locals, cookies } = getRequestEvent();
46
47 // return cached result if available
48 if (locals.auth) {
49 return locals.auth;
50 }
51
52 const did = getSignedCookie(cookies, SESSION_COOKIE);
53 if (!did) {
54 error(401, `not signed in`);
55 }
56
57 if (!isDid(did)) {
58 cookies.delete(SESSION_COOKIE, { path: '/' });
59 error(401, `not signed in`);
60 }
61
62 try {
63 const session = await oauth.restore(did);
64 const client = new Client({ handler: session });
65
66 const auth: AuthContext = {
67 session: { did },
68 client,
69 };
70
71 locals.auth = auth;
72 return auth;
73 } catch (err) {
74 if (isSessionInvalidError(err)) {
75 cookies.delete(SESSION_COOKIE, { path: '/' });
76
77 error(401, `session expired`);
78 }
79
80 throw err;
81 }
82};