Skip to content

Commit

Permalink
feat(auth): handle code exchange server-side
Browse files Browse the repository at this point in the history
  • Loading branch information
vladjerca authored and seferturan committed Jan 10, 2025
1 parent 37ca829 commit e8b2f36
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -1,57 +1,16 @@
<script lang="ts">
import { replaceState } from "$app/navigation";
import { page } from "$app/stores";
import { onMount } from "svelte";
import { AuthEndpoint } from "../AuthEndpoint";
import type { ClientAuthResponse } from "../models/SerializedAuthResponse";
import { provisionAuth, useAuth } from "../stores/useAuth";
import { provisionAuth } from "../stores/useAuth";
type AuthProviderProps = {
url: string;
isAuthorized: boolean;
} & ChildrenProps;
const { isAuthorized, url, children }: AuthProviderProps = $props();
provisionAuth({
isAuthorized,
url,
});
const store = useAuth();
function requestAuthStatus(code: string) {
return fetch(AuthEndpoint.Exchange, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ code }),
}).then((res) => res.json() as Promise<ClientAuthResponse>);
}
onMount(async () => {
const url = new URL($page.url.href);
const queryParams = url.searchParams;
const code = queryParams.get("code");
if (!code) {
return;
}
const { isAuthorized } = await requestAuthStatus(code);
store.isAuthorized.set(isAuthorized);
if (!isAuthorized) {
return;
}
queryParams.delete("code");
replaceState(
`${url.pathname}${queryParams.toString() ? "?" + queryParams.toString() : ""}`,
{},
);
});
</script>

{@render children()}
54 changes: 30 additions & 24 deletions projects/client/src/lib/features/auth/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,39 +31,43 @@ export const handle: Handle = async ({ event, resolve }) => {
});
}

const isExchange = event.url.pathname.startsWith(AuthEndpoint.Exchange);
const code = event.url.searchParams.get('code');
const isExchange = code != null;

if (isExchange) {
const { code } = await event.request.json() as { code: string };
const referrer = event.request.headers.get('referer') ?? '';

const result = await authorize({ code, referrer });
const { isAuthorized } = result;
setAuth(result);

const cookieHeader = isAuthorized
? {
'Set-Cookie': event.cookies.serialize(
AUTH_COOKIE_NAME,
await encrypt(key, result),
{
httpOnly: true,
secure: true,
maxAge: result.expiresAt ?? 0,
path: '/',
},
),
}
: {} as Record<string, string>;

return new Response(
JSON.stringify({
isAuthorized,
}),
{
headers: { ...cookieHeader },
const url = new URL(event.url);
url.searchParams.delete('code');

const headers = new Headers();

if (isAuthorized) {
const cookie = event.cookies.serialize(
AUTH_COOKIE_NAME,
await encrypt(key, result),
{
httpOnly: true,
secure: true,
maxAge: result.expiresAt ?? 0,
path: '/',
},
);

headers.set('Set-Cookie', cookie);
}

return new Response(null, {
status: 302,
headers: {
...Object.fromEntries(headers),
Location: url.toString(),
},
);
});
}

/**
Expand All @@ -82,6 +86,8 @@ export const handle: Handle = async ({ event, resolve }) => {
maxAge: 0,
path: '/',
});

return await resolve(event);
}

return await resolve(event);
Expand Down

0 comments on commit e8b2f36

Please sign in to comment.