oidc authentication

This commit is contained in:
2025-08-09 00:31:35 +02:00
parent 2c9b44d215
commit 5f4201428a
34 changed files with 1766 additions and 84 deletions

View File

@@ -1,6 +1,7 @@
export async function logout() {
useAuthSession().value = null;
useAdminStore().$reset();
useWarrenStore().$reset();
await navigateTo({
path: '/login',
});

View File

@@ -0,0 +1,74 @@
import type { ApiResponse } from '~/shared/types/api';
import { getApiHeaders } from '..';
import { toast } from 'vue-sonner';
import type { AuthUser } from '~/shared/types/auth';
export async function getRedirectUrl(): Promise<
{ success: true; url: string } | { success: false }
> {
const { data, error } = await useFetch<ApiResponse<string>>(
getApiUrl('auth/oidc'),
{
method: 'GET',
headers: getApiHeaders(false),
responseType: 'json',
}
);
if (data.value == null) {
toast.error('OpenID Connect', {
description: error.value?.data ?? 'Failed to get OIDC redirect',
});
return {
success: false,
};
}
return {
success: true,
url: data.value.data,
};
}
export async function oidcLoginUser(
code: string,
state: string
): Promise<{ success: boolean }> {
const { data, error } = await useFetch<
ApiResponse<{ token: string; user: AuthUser; expiresAt: number }>
>(getApiUrl(`auth/oidc/login?code=${code}&state=${state}`), {
method: 'GET',
headers: getApiHeaders(false),
responseType: 'json',
retry: false,
});
if (data.value == null) {
toast.error('OpenID Connect', {
description: error.value?.data ?? 'Failed to login with OIDC',
});
return {
success: false,
};
}
const token = data.value.data.token;
const { user, expiresAt } = data.value.data;
useAuthSession().value = {
type: 'WarrenAuth',
id: token,
user,
expiresAt,
};
toast.success('OpenID Connect', {
description: `Successfully logged in`,
});
return {
success: true,
};
}

View File

@@ -10,6 +10,7 @@ import {
import { toTypedSchema } from '@vee-validate/yup';
import { useForm } from 'vee-validate';
import { loginUser } from '~/lib/api/auth/login';
import { getRedirectUrl, oidcLoginUser } from '~/lib/api/auth/oidc';
import { loginSchema } from '~/lib/schemas/auth';
definePageMeta({
@@ -20,10 +21,31 @@ useHead({
title: 'Login - Warren',
});
const route = useRoute();
// TODO: Get this from the backend
const OPEN_ID = false;
const OPEN_ID = true;
const loggingIn = ref(false);
if (
route.query.code &&
typeof route.query.code === 'string' &&
route.query.state &&
typeof route.query.state === 'string'
) {
console.log('SEND');
loggingIn.value = true;
const { success } = await oidcLoginUser(
route.query.code,
route.query.state
);
loggingIn.value = false;
if (success) {
await navigateTo({ path: '/' });
}
}
const form = useForm({
validationSchema: toTypedSchema(loginSchema),
});
@@ -43,6 +65,24 @@ const onSubmit = form.handleSubmit(async (values) => {
loggingIn.value = false;
});
async function oidcClicked() {
if (loggingIn.value) {
return;
}
loggingIn.value = true;
const result = await getRedirectUrl();
if (result.success) {
await navigateTo(result.url, {
external: true,
});
} else {
loggingIn.value = false;
}
}
</script>
<template>
@@ -97,7 +137,11 @@ const onSubmit = form.handleSubmit(async (values) => {
:disabled="loggingIn"
>Log in</Button
>
<Button class="w-full" variant="outline" :disabled="!OPEN_ID"
<Button
class="w-full"
variant="outline"
:disabled="!OPEN_ID || loggingIn"
@click="oidcClicked"
>OpenID Connect</Button
>
<NuxtLink to="/register" class="w-full">