Compare commits
5 Commits
develop
...
feature/au
Author | SHA1 | Date | |
---|---|---|---|
ef51513fe1 | |||
94514ec965 | |||
f9a27cbbb7 | |||
69150caab3 | |||
2ed0b70780 |
@ -1,28 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { LucideLoaderCircle } from '@lucide/svelte';
|
|
||||||
import { Button } from '$lib/components/ui/button';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
providerName: string;
|
|
||||||
displayName: string;
|
|
||||||
iconSrc: string;
|
|
||||||
inviteToken?: string;
|
|
||||||
}
|
|
||||||
let { providerName, displayName, inviteToken, iconSrc }: Props = $props();
|
|
||||||
|
|
||||||
let submitted = $state(false);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<form method="get" onsubmit={() => (submitted = true)} action="/auth/{providerName}">
|
|
||||||
{#if inviteToken}
|
|
||||||
<input type="hidden" value={inviteToken} name="invite" />
|
|
||||||
{/if}
|
|
||||||
<Button type="submit" disabled={submitted}>
|
|
||||||
{#if submitted}
|
|
||||||
<LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
|
||||||
{:else}
|
|
||||||
<img class="mr-2 h-4 w-4" alt="{displayName} Logo" src={iconSrc} />
|
|
||||||
{/if}
|
|
||||||
Sign {inviteToken ? 'up' : 'in'} with {displayName}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
@ -1,26 +1,54 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { LucideLoaderCircle } from '@lucide/svelte';
|
||||||
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { cn } from '$lib/utils.js';
|
import { cn } from '$lib/utils.js';
|
||||||
import googleIcon from '$lib/assets/google.svg';
|
import googleIcon from '$lib/assets/google.svg';
|
||||||
import { enabledAuthProviders } from '$lib/auth';
|
import { enabledAuthProviders } from '$lib/auth';
|
||||||
import AuthButton from './auth-button.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
let { inviteToken, class: className, ...rest }: {
|
||||||
inviteToken?: string;
|
inviteToken?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
}
|
rest?: { [p: string]: unknown }
|
||||||
let { inviteToken, class: className }: Props = $props();
|
} = $props();
|
||||||
|
|
||||||
|
let submitted = $state(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={cn('flex gap-6', className)}>
|
<div class={cn('flex gap-6', className)} {...rest}>
|
||||||
{#if enabledAuthProviders.authentik}
|
{#if enabledAuthProviders.authentik }
|
||||||
<AuthButton
|
<form method="get" onsubmit={() => submitted = true}
|
||||||
providerName="authentik"
|
action="/auth/authentik{inviteToken ? `?invite=${inviteToken}` : ''}">
|
||||||
displayName="Authentik"
|
<input type="hidden" value={inviteToken} name="invite" />
|
||||||
iconSrc="https://auth.cazzzer.com/static/dist/assets/icons/icon.svg"
|
<Button type="submit" disabled={submitted}>
|
||||||
{inviteToken}
|
{#if submitted}
|
||||||
/>
|
<LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
{:else}
|
||||||
|
<img
|
||||||
|
class="mr-2 h-4 w-4"
|
||||||
|
alt="Authentik Logo"
|
||||||
|
src="https://auth.cazzzer.com/static/dist/assets/icons/icon.svg"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
Sign in with Authentik
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{#if enabledAuthProviders.google}
|
{#if enabledAuthProviders.google }
|
||||||
<AuthButton providerName="google" displayName="Google" iconSrc={googleIcon} {inviteToken} />
|
<form method="get" onsubmit={() => submitted = true}
|
||||||
|
action="/auth/google{inviteToken ? `?invite=${inviteToken}` : ''}">
|
||||||
|
<input type="hidden" value={inviteToken} name="invite" />
|
||||||
|
<Button type="submit" disabled={submitted}>
|
||||||
|
{#if submitted}
|
||||||
|
<LucideLoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
{:else}
|
||||||
|
<img
|
||||||
|
class="mr-2 h-4 w-4"
|
||||||
|
alt="Google Logo"
|
||||||
|
src={googleIcon}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
Sign in with Google
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,24 +3,24 @@ import { oauthProviders } from '$lib/server/oauth';
|
|||||||
import { is } from 'typia';
|
import { is } from 'typia';
|
||||||
import { type AuthProvider, enabledAuthProviders } from '$lib/auth';
|
import { type AuthProvider, enabledAuthProviders } from '$lib/auth';
|
||||||
|
|
||||||
export async function GET({ params: { provider }, url, cookies }) {
|
export async function GET(event) {
|
||||||
|
const { provider } = event.params;
|
||||||
if (!is<AuthProvider>(provider) || !enabledAuthProviders[provider]) {
|
if (!is<AuthProvider>(provider) || !enabledAuthProviders[provider]) {
|
||||||
return new Response(null, { status: 404 });
|
return new Response(null, { status: 404 });
|
||||||
}
|
}
|
||||||
const oauthProvider = oauthProviders[provider];
|
const oauthProvider = oauthProviders[provider];
|
||||||
|
|
||||||
const inviteToken = url.searchParams.get('invite') ?? '';
|
|
||||||
const state = generateState();
|
const state = generateState();
|
||||||
const codeVerifier = generateCodeVerifier();
|
const codeVerifier = generateCodeVerifier();
|
||||||
const authUrl = oauthProvider.createAuthorizationURL(state + inviteToken, codeVerifier);
|
const url = oauthProvider.createAuthorizationURL(state, codeVerifier);
|
||||||
|
|
||||||
cookies.set(`${provider}_oauth_state`, state, {
|
event.cookies.set(`${provider}_oauth_state`, state, {
|
||||||
path: '/',
|
path: '/',
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 60 * 10, // 10 minutes
|
maxAge: 60 * 10, // 10 minutes
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
});
|
});
|
||||||
cookies.set(`${provider}_code_verifier`, codeVerifier, {
|
event.cookies.set(`${provider}_code_verifier`, codeVerifier, {
|
||||||
path: '/',
|
path: '/',
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 60 * 10, // 10 minutes
|
maxAge: 60 * 10, // 10 minutes
|
||||||
@ -30,7 +30,7 @@ export async function GET({ params: { provider }, url, cookies }) {
|
|||||||
return new Response(null, {
|
return new Response(null, {
|
||||||
status: 302,
|
status: 302,
|
||||||
headers: {
|
headers: {
|
||||||
Location: authUrl.toString(),
|
Location: url.toString(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import type { LayoutServerLoad } from './$types';
|
|||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
import { isValidInviteToken } from '$lib/server/auth';
|
import { isValidInviteToken } from '$lib/server/auth';
|
||||||
|
|
||||||
export const load: LayoutServerLoad = ({ params, locals }) => {
|
export const load: LayoutServerLoad = ({ params }) => {
|
||||||
if (!isValidInviteToken(params.id)) redirect(302, '/');
|
if (!isValidInviteToken(params.id)) redirect(307, '/')
|
||||||
if (locals.user !== null) redirect(302, '/');
|
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<h1 class="mb-2 scroll-m-20 text-center text-3xl font-extrabold tracking-tight lg:text-4xl">
|
<h1 class="mb-2 scroll-m-20 text-center text-3xl font-extrabold tracking-tight lg:text-4xl">
|
||||||
You are invited to VPGen
|
Welcome to VPGen
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<AuthForm {inviteToken} />
|
<AuthForm inviteToken={inviteToken} />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user