Created
November 28, 2023 19:32
-
-
Save claughinghouse/86bcc219368f946fbdc8a3b69e459b66 to your computer and use it in GitHub Desktop.
SvelteKit and SST Auth
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is in the sveltekit parent directory and is a seperate stack for SST. | |
import { Account } from "@rebut/core/account"; | |
import { Config } from "sst/node/config"; | |
import { AuthHandler, GoogleAdapter } from "sst/node/future/auth"; | |
import { sessions } from "./sessions"; | |
export const handler = AuthHandler({ | |
sessions, | |
providers: { | |
google: GoogleAdapter({ | |
mode: "oidc", | |
clientID: Config.GOOGLE_CLIENT_ID, | |
}), | |
}, | |
callbacks: { | |
auth: { | |
async allowClient(clientID, redirect) { | |
return true; | |
}, | |
async success(input, response) { | |
const claims = input.tokenset.claims(); | |
const email = claims.email; | |
if (!claims.email) throw new Error("No email found"); | |
let accountID = await Account.fromEmail(claims.email).then( | |
(x) => x?.accountID | |
); | |
if (!accountID) { | |
// console.log("No account found, creating new account:", claims.email); | |
const createAccount = await Account.create({ | |
email: claims.email, | |
emailVerified: claims.email_verified!, | |
avatar: claims.picture?.replace("s96-c", "s400-c") || "", | |
name: claims.name!, | |
givenName: claims.given_name, | |
familyName: claims.family_name, | |
}); | |
// console.log("Account created:", accountID); | |
accountID = createAccount.accountID; | |
} | |
return response.session({ | |
type: "account", | |
properties: { | |
accountID: accountID!, | |
}, | |
}); | |
}, | |
}, | |
}, | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// See https://kit.svelte.dev/docs/types#app | |
// for information about these interfaces | |
declare global { | |
namespace App { | |
// interface Error {} | |
interface Locals { | |
account: Account | null; | |
} | |
// interface PageData {} | |
// interface Platform {} | |
} | |
} | |
export {}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { checkAuth } from '$lib/server/auth'; | |
import { redirect, type Handle } from '@sveltejs/kit'; | |
export const handle: Handle = async ({ event, resolve }) => { | |
// validate the user on any request | |
event.locals.account = checkAuth(event); | |
if (event.url.pathname.startsWith('/dashboard')) { | |
if (!event.locals.account) { | |
throw redirect(302, '/'); | |
} | |
} | |
const response = await resolve(event); | |
return response; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { RequestEvent } from '@sveltejs/kit'; | |
import { Session } from 'sst/node/future/auth'; | |
export const checkAuth = (event: RequestEvent) => { | |
const { cookies } = event; | |
const accountToken = cookies.get('auth_token'); | |
if (accountToken) { | |
const session = Session.verify(accountToken); | |
// If the auth_token cookie is present but its not valid, eat the cookie. | |
if (session.type === 'public') { | |
// console.log('invalid session'); | |
cookies.set('auth_token', '', { | |
path: '/', | |
expires: new Date(0) | |
}); | |
} | |
// console.log('session in Auth lib', session); | |
return session; | |
} | |
return null; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { PageServerLoad } from './$types'; | |
export const load: PageServerLoad = async ({ locals }) => { | |
// console.log('locals', locals); | |
return { | |
account: locals.account | |
}; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import { page } from '$app/stores'; | |
import { PUBLIC_VITE_AUTH_URL } from '$env/static/public'; | |
import type { PageData } from './$types'; | |
export let data: PageData; | |
const params = new URLSearchParams({ | |
client_id: 'sk', | |
redirect_uri: $page.url.origin + '/auth/callback', | |
response_type: 'code', | |
provider: 'google' | |
}); | |
let loginUrl = `${PUBLIC_VITE_AUTH_URL}` + '/authorize?' + params.toString(); | |
</script> | |
<h1>Welcome to SvelteKit</h1> | |
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p> | |
{#if data.account} | |
<p>Go to the <a href="/dashboard">dashboard</a></p> | |
<form action="/auth/logout" method="POST"> | |
<button type="submit">Log out</button> | |
</form> | |
{:else} | |
<p>Not logged in</p> | |
<button id="home_sk3"> | |
<a href={loginUrl}>Login with Google</a> | |
</button> | |
{/if} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { PUBLIC_VITE_AUTH_URL } from '$env/static/public'; | |
import { error } from '@sveltejs/kit'; | |
export async function GET(evt) { | |
const code = evt.url.searchParams.get('code'); | |
if (code === null || code.trim() === '') { | |
throw error(400, { | |
message: 'Missing code. <a href="/">Try again</a>' | |
}); | |
} | |
const response = await fetch(`${PUBLIC_VITE_AUTH_URL}` + '/token', { | |
method: 'POST', | |
body: new URLSearchParams({ | |
grant_type: 'authorization_code', | |
client_id: 'sk', | |
code, | |
redirect_uri: `${evt.url.origin}${evt.url.pathname}` | |
}) | |
}).then((r) => r.json()); | |
evt.cookies.set('auth_token', response.access_token, { | |
path: '/', | |
sameSite: 'lax', | |
httpOnly: true, | |
maxAge: 60 * 60 * 24, // 60 seconds * 60 minutes * 24 = 1 day | |
secure: import.meta.env.NODE_ENV === 'production' | |
}); | |
return new Response('Redirect', { | |
status: 302, | |
headers: { Location: `${evt.url.origin}/dashboard` } | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { redirect } from '@sveltejs/kit'; | |
import type { Actions, PageServerLoad } from './$types'; | |
export const load: PageServerLoad = async () => { | |
// we only use this endpoint for the api | |
// and don't need to see the page | |
throw redirect(302, '/'); | |
}; | |
export const actions: Actions = { | |
default({ cookies }) { | |
// eat the cookie | |
cookies.set('auth_token', '', { | |
path: '/', | |
expires: new Date(0) | |
}); | |
// redirect the user | |
throw redirect(302, '/'); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { redirect } from '@sveltejs/kit'; | |
import type { PageServerLoad } from './$types'; | |
export const load: PageServerLoad = async ({ locals }) => { | |
if (locals.account.type !== 'account') { | |
throw redirect(302, '/'); | |
} | |
return { | |
account: locals.account | |
}; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts"> | |
import type { PageData } from './$types'; | |
export let data: PageData; | |
// console.log('dashboard route', data); | |
</script> | |
<h1>Welcome to SvelteKit</h1> | |
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p> | |
<p>Logged in with accountID {data.account.properties.accountID}</p> | |
<p>Go to the <a href="/">home</a></p> | |
<form action="/auth/logout" method="POST"> | |
<button type="submit">Log out</button> | |
</form> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment