import {addRouteMiddleware, defineNuxtPlugin, navigateTo, useCookie} from '#app' import useAuth from "./composables/useAuth" import {RouteLocationNormalized} from "vue-router"; import {ModuleOptions} from "../module"; interface AccessToken { access_token: string, token_type: string, expires_in: number, refresh_token: string scope: string } export default defineNuxtPlugin(() => { const resolveUsingToken = async ( to: RouteLocationNormalized, authConfig: ModuleOptions, setBearerToken: (token: string, tokenType: string, expires: number) => Promise ) => { const hashParams = new URLSearchParams(to.hash.substring(1)) if (hashParams.has('access_token')) { const token = hashParams.get('access_token') as string; const tokenType = hashParams.get('token_type') as string; const expires = hashParams.get('expires_in') as string; await setBearerToken(token, tokenType, parseInt(expires)); return navigateTo(authConfig.redirect.home) } } const resolveUsingCode = async ( to: RouteLocationNormalized, authConfig: ModuleOptions, setBearerToken: (token: string, tokenType: string, expires: number) => Promise, setRefreshToken: (token: string, tokenType: string, expires: number) => Promise ) => { if (to.query['code']) { const code = to.query['code'] as string; const stateFromRequest = to.query['state'] as string; const stateFromCookie = useCookie('oauth_state'); const codeVerifier = useCookie('oauth_code_verifier'); if (stateFromRequest !== stateFromCookie.value) { console.warn('State mismatch', stateFromRequest, stateFromCookie.value) return navigateTo(authConfig.redirect.login) } const formData = new FormData(); formData.append('grant_type', 'authorization_code') formData.append('client_id', authConfig.clientId) formData.append('redirect_uri', window.location.origin + authConfig.redirect.callback) formData.append('code_verifier', codeVerifier.value) formData.append('code', code) const response: Response = await fetch(authConfig.endpoints.token, { method: 'POST', body: formData, }) if (!response.ok) { console.warn('Failed to fetch token', response) return navigateTo(authConfig.redirect.login) } const data: AccessToken = await response.json(); await setBearerToken(data.access_token, data.token_type, data.expires_in) await setRefreshToken(data.refresh_token, data.token_type, authConfig.refreshToken.maxAge) return navigateTo(authConfig.redirect.home) } } addRouteMiddleware('auth', async (to) => { const {user, authConfig, setBearerToken, setRefreshToken} = await useAuth() if (to.path === authConfig.redirect.callback) { const queryParams = new URLSearchParams(to.query.toString()); if (queryParams.has('error')) { return navigateTo(authConfig.redirect.login) } if (authConfig.responseType === 'token') { return await resolveUsingToken(to, authConfig, setBearerToken) } if (authConfig.responseType === 'code') { return await resolveUsingCode(to, authConfig, setBearerToken, setRefreshToken) } return } if (user.value === undefined) { return navigateTo(authConfig.redirect.login) } }) addRouteMiddleware('guest', async () => { const {user, authConfig} = await useAuth() if (user.value !== undefined) { return navigateTo(authConfig.redirect.home) } }) })