Enhance OAuth token handling in authentication flow; update frontend to support access and refresh tokens. Refactor auth store to manage refresh token state and improve token storage logic.

This commit is contained in:
mohamad 2025-05-16 22:08:56 +02:00
parent 9ff293b850
commit f2ac73502c
3 changed files with 39 additions and 17 deletions

View File

@ -37,12 +37,16 @@ async def google_callback(request: Request, db: AsyncSession = Depends(get_async
# Generate JWT token # Generate JWT token
strategy = fastapi_users._auth_backends[0].get_strategy() strategy = fastapi_users._auth_backends[0].get_strategy()
token = await strategy.write_token(user_to_login) token_response = await strategy.write_token(user_to_login)
access_token = token_response["access_token"]
refresh_token = token_response.get("refresh_token") # Use .get for safety, though it should be there
# Redirect to frontend with tokens
redirect_url = f"{settings.FRONTEND_URL}/auth/callback?access_token={access_token}"
if refresh_token:
redirect_url += f"&refresh_token={refresh_token}"
# Redirect to frontend with token return RedirectResponse(url=redirect_url)
return RedirectResponse(
url=f"{settings.FRONTEND_URL}/auth/callback?token={token}"
)
@router.get('/apple/login') @router.get('/apple/login')
async def apple_login(request: Request): async def apple_login(request: Request):
@ -83,9 +87,13 @@ async def apple_callback(request: Request, db: AsyncSession = Depends(get_async_
# Generate JWT token # Generate JWT token
strategy = fastapi_users._auth_backends[0].get_strategy() strategy = fastapi_users._auth_backends[0].get_strategy()
token = await strategy.write_token(user_to_login) token_response = await strategy.write_token(user_to_login)
access_token = token_response["access_token"]
# Redirect to frontend with token refresh_token = token_response.get("refresh_token") # Use .get for safety
return RedirectResponse(
url=f"{settings.FRONTEND_URL}/auth/callback?token={token}" # Redirect to frontend with tokens
) redirect_url = f"{settings.FRONTEND_URL}/auth/callback?access_token={access_token}"
if refresh_token:
redirect_url += f"&refresh_token={refresh_token}"
return RedirectResponse(url=redirect_url)

View File

@ -28,12 +28,17 @@ const error = ref<string | null>(null);
onMounted(async () => { onMounted(async () => {
try { try {
const token = route.query.token as string; const accessToken = route.query.access_token as string | undefined;
if (!token) { const refreshToken = route.query.refresh_token as string | undefined;
const legacyToken = route.query.token as string | undefined;
const tokenToUse = accessToken || legacyToken;
if (!tokenToUse) {
throw new Error('No token provided'); throw new Error('No token provided');
} }
await authStore.setTokens({ access_token: token, refresh_token: '' }); await authStore.setTokens({ access_token: tokenToUse, refresh_token: refreshToken });
notificationStore.addNotification({ message: 'Login successful', type: 'success' }); notificationStore.addNotification({ message: 'Login successful', type: 'success' });
router.push('/'); router.push('/');
} catch (err) { } catch (err) {

View File

@ -7,6 +7,7 @@ import router from '@/router';
interface AuthState { interface AuthState {
accessToken: string | null; accessToken: string | null;
refreshToken: string | null;
user: { user: {
email: string; email: string;
name: string; name: string;
@ -17,6 +18,7 @@ interface AuthState {
export const useAuthStore = defineStore('auth', () => { export const useAuthStore = defineStore('auth', () => {
// State // State
const accessToken = ref<string | null>(localStorage.getItem('token')); const accessToken = ref<string | null>(localStorage.getItem('token'));
const refreshToken = ref<string | null>(localStorage.getItem('refreshToken'));
const user = ref<AuthState['user']>(null); const user = ref<AuthState['user']>(null);
// Getters // Getters
@ -24,15 +26,21 @@ export const useAuthStore = defineStore('auth', () => {
const getUser = computed(() => user.value); const getUser = computed(() => user.value);
// Actions // Actions
const setTokens = (tokens: { access_token: string }) => { const setTokens = (tokens: { access_token: string; refresh_token?: string }) => {
accessToken.value = tokens.access_token; accessToken.value = tokens.access_token;
localStorage.setItem('token', tokens.access_token); localStorage.setItem('token', tokens.access_token);
if (tokens.refresh_token) {
refreshToken.value = tokens.refresh_token;
localStorage.setItem('refreshToken', tokens.refresh_token);
}
}; };
const clearTokens = () => { const clearTokens = () => {
accessToken.value = null; accessToken.value = null;
refreshToken.value = null;
user.value = null; user.value = null;
localStorage.removeItem('token'); localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
}; };
const setUser = (userData: AuthState['user']) => { const setUser = (userData: AuthState['user']) => {
@ -66,8 +74,8 @@ export const useAuthStore = defineStore('auth', () => {
}, },
}); });
const { access_token } = response.data; const { access_token, refresh_token } = response.data;
setTokens({ access_token }); setTokens({ access_token, refresh_token });
await fetchCurrentUser(); await fetchCurrentUser();
return response.data; return response.data;
}; };
@ -85,6 +93,7 @@ export const useAuthStore = defineStore('auth', () => {
return { return {
accessToken, accessToken,
user, user,
refreshToken,
isAuthenticated, isAuthenticated,
getUser, getUser,
setTokens, setTokens,