Files
htwkalender/frontend/src/view/LoginView.vue
2024-11-26 18:18:18 +01:00

141 lines
3.7 KiB
Vue

<template>
<div id="app">
<h1>OAuth2 Authentication with Vue 3</h1>
<p>Public Content: {{ publicContent }}</p>
<div v-if="authenticated">
<h2>Private Content</h2>
<p>{{ privateContent }}</p>
<button @click="logout">Logout</button>
</div>
<div v-else>
<p>Please log in to see the private content.</p>
<ul>
<li v-for="provider in authProviders" :key="provider.name">
<a :href="provider.authURL + redirectUri" @click="storeProvider(provider)">
Login with {{ provider.name }}
</a>
</li>
</ul>
</div>
</div>
</template>
<script lang="ts" setup>
import {ref, onMounted, Ref} from 'vue';
import PocketBase, {AuthProviderInfo} from 'pocketbase';
// Reactive state variables
const authenticated = ref(false);
const publicContent = ref('');
const privateContent = ref('');
const accessToken = ref<string | null>(null);
const authProviders: Ref<AuthProviderInfo[]> = ref([]); // Array for OAuth2 providers
// PocketBase instance and redirect URI
const pb = new PocketBase('http://127.0.0.1:8090');
const redirectUri = 'http://localhost:8000/callback';
// Load OAuth2 providers
const loadLinks = async () => {
try {
const authMethods = await pb.collection('users').listAuthMethods();
authProviders.value = authMethods.oauth2.providers || [];
} catch (error) {
console.error('Error loading OAuth2 providers:', error);
}
};
// Store provider data in localStorage for later use
const storeProvider = (provider: AuthProviderInfo) => {
localStorage.setItem('provider', JSON.stringify(provider));
};
// Fetch public content
const fetchPublicContent = async () => {
try {
const response = await fetch('http://localhost:8081/public');
if (!response.ok) {
throw new Error('Failed to fetch public content');
}
publicContent.value = await response.text();
} catch (error) {
console.error('Error fetching public content:', error);
}
};
// Fetch private content
const fetchPrivateContent = async () => {
if (accessToken.value) {
try {
const response = await fetch('http://localhost:8081/private', {
headers: {
Authorization: `Bearer ${accessToken.value}`,
},
});
if (!response.ok) {
throw new Error('Failed to fetch private content');
}
privateContent.value = await response.text();
} catch (error) {
console.error('Error fetching private content:', error);
}
}
};
// Handle OAuth2 callback
const handleCallback = async () => {
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
const state = urlParams.get('state');
if (code && state) {
try {
// Exchange authorization code for access token
const provider = JSON.parse(localStorage.getItem('provider') || '{}');
const authData = await pb.collection('users').authWithOAuth2(
provider.name,
code,
state,
redirectUri
);
accessToken.value = authData.token;
authenticated.value = true;
// Fetch private content after successful login
fetchPrivateContent();
} catch (error) {
console.error('Error handling OAuth2 callback:', error);
}
}
};
// Logout function
const logout = () => {
authenticated.value = false;
accessToken.value = null;
window.location.href = '/';
};
// Lifecycle hook
onMounted(() => {
fetchPublicContent();
loadLinks();
// Check for OAuth2 callback
if (window.location.pathname === '/callback') {
handleCallback();
}
});
</script>
<style scoped>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
text-align: center;
color: #2c3e50;
}
</style>