create superform for oauth callback
This commit is contained in:
parent
093b7a8135
commit
b0935402c0
2 changed files with 71 additions and 19 deletions
|
@ -1,4 +1,12 @@
|
||||||
import { Google, Discord, GitHub, generateState, generateCodeVerifier } from 'arctic'
|
import {
|
||||||
|
Google,
|
||||||
|
Discord,
|
||||||
|
GitHub,
|
||||||
|
generateState,
|
||||||
|
generateCodeVerifier,
|
||||||
|
type GitHubTokens,
|
||||||
|
type DiscordTokens
|
||||||
|
} from 'arctic'
|
||||||
import { error, redirect, type Actions, type RequestHandler, type ServerLoad } from '@sveltejs/kit'
|
import { error, redirect, type Actions, type RequestHandler, type ServerLoad } from '@sveltejs/kit'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { db, publicUser } from './db'
|
import { db, publicUser } from './db'
|
||||||
|
@ -6,8 +14,9 @@ import { env } from '$env/dynamic/private'
|
||||||
import { dev } from '$app/environment'
|
import { dev } from '$app/environment'
|
||||||
import { alphabet, generateRandomString } from 'oslo/crypto'
|
import { alphabet, generateRandomString } from 'oslo/crypto'
|
||||||
import { decodeJwt } from 'jose'
|
import { decodeJwt } from 'jose'
|
||||||
import { superForm, type SuperForm } from 'sveltekit-superforms'
|
import { superValidate, type SuperForm } from 'sveltekit-superforms'
|
||||||
import { zod, type ValidationAdapter } from 'sveltekit-superforms/adapters'
|
import { zod, type ValidationAdapter } from 'sveltekit-superforms/adapters'
|
||||||
|
import { cookieController, createSessionForUser } from './auth'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
DISCORD_CLIENT_ID,
|
DISCORD_CLIENT_ID,
|
||||||
|
@ -158,24 +167,50 @@ export function oauth_callback(): ServerLoad<
|
||||||
) {
|
) {
|
||||||
error(400, 'Invalid request')
|
error(400, 'Invalid request')
|
||||||
}
|
}
|
||||||
let tokens
|
let id: string
|
||||||
let id
|
let name: string
|
||||||
let name
|
|
||||||
if (provider instanceof Google) {
|
if (provider instanceof Google) {
|
||||||
tokens = await provider.validateAuthorizationCode(code, storedCodeVerifier)
|
const tokens = await provider.validateAuthorizationCode(code, storedCodeVerifier)
|
||||||
console.log(tokens.idToken)
|
console.log(tokens.idToken)
|
||||||
const { sub, name: Uname } = decodeJwt(tokens.idToken)
|
const { sub, name: Uname } = decodeJwt(tokens.idToken)
|
||||||
id = sub
|
id = sub!
|
||||||
name = Uname
|
name = Uname as string
|
||||||
} else {
|
} else {
|
||||||
tokens = await provider.validateAuthorizationCode(code)
|
const tokens: GitHubTokens | DiscordTokens = await provider.validateAuthorizationCode(code)
|
||||||
|
if (providerID === 'discord') {
|
||||||
|
const response = await fetch('https://discord.com/api/users/@me', {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens.accessToken}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!response.ok) error(500, 'Unable to contact provider')
|
||||||
|
const { id: userId, username } = await response.json()
|
||||||
|
id = userId
|
||||||
|
name = username
|
||||||
|
} else if (providerID === 'github') {
|
||||||
|
const response = await fetch('https://api.github.com/user', {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens.accessToken}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!response.ok) error(500, 'Unable to contact provider')
|
||||||
|
const { id: userId, login } = await response.json()
|
||||||
|
id = userId
|
||||||
|
name = login
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const existingUser = (await db.user.getOneBySecondaryIndex(`oauth_${providerID}_id`, id))?.flat()
|
||||||
|
if(existingUser) {
|
||||||
|
const session = await createSessionForUser(existingUser.id)
|
||||||
|
const sessionCookie = cookieController.createCookie(session.unwrap().id)
|
||||||
|
cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
|
path: '.',
|
||||||
|
...sessionCookie.attributes
|
||||||
|
})
|
||||||
|
redirect(302, '/app')
|
||||||
}
|
}
|
||||||
const formToken = generateRandomString(12, alphabet('0-9', 'a-z'))
|
const formToken = generateRandomString(12, alphabet('0-9', 'a-z'))
|
||||||
const form = superForm(
|
const form = await superValidate({ token: formToken }, zod(z.object({ token: z.string() })))
|
||||||
zod(z.object({ token: z.string() }), {
|
|
||||||
defaults: { token: formToken }
|
|
||||||
})
|
|
||||||
)
|
|
||||||
if (locals.user) {
|
if (locals.user) {
|
||||||
// the user is already logged in, ask them if they want to link the account to their existing account, or log out and try again
|
// the user is already logged in, ask them if they want to link the account to their existing account, or log out and try again
|
||||||
await db.saved_oauth_data.set(formToken, {
|
await db.saved_oauth_data.set(formToken, {
|
||||||
|
@ -207,5 +242,12 @@ export function oauth_callback(): ServerLoad<
|
||||||
}
|
}
|
||||||
|
|
||||||
export function oauth_callback_actions(): Actions<{ provider: string }> {
|
export function oauth_callback_actions(): Actions<{ provider: string }> {
|
||||||
return {}
|
return {
|
||||||
|
link: ({ request, locals, }) => {
|
||||||
|
// get existing account and link it
|
||||||
|
},
|
||||||
|
create: ({ request }) => {
|
||||||
|
// create new account with
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { superForm } from 'sveltekit-superforms'
|
||||||
|
|
||||||
const { data } = $props()
|
const { data } = $props()
|
||||||
|
const { enhance } = superForm(data.form)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if data.type === 'create'}
|
<form action="POST" use:enhance>
|
||||||
|
{#if data.type === 'create'}
|
||||||
do you want to create a new account using <code class="font-bold">{data.name}</code> from {data.prov}?
|
do you want to create a new account using <code class="font-bold">{data.name}</code> from {data.prov}?
|
||||||
<button>yes</button> <button>no</button>
|
<button formaction="?/create">yes</button> <a href="/">no</a>
|
||||||
{:else if data.type === 'link'}{/if}
|
{:else if data.type === 'link'}
|
||||||
|
do you want to link <code class="font-bold">{data.name}</code> from {data.prov} to your existing
|
||||||
|
account {data.user.displayName}?
|
||||||
|
<button formaction="?/link">yes</button> <a href="/">no</a>
|
||||||
|
<a href="/auth/signout">Sign me out and try again</a>
|
||||||
|
{/if}
|
||||||
|
</form>
|
||||||
|
|
Loading…
Reference in a new issue