From 6c75faae4adb78e3e860c16c6ea31cd1a9069a17 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Sun, 18 Jan 2026 21:35:11 +0100 Subject: [PATCH] fix: cleanup line number artifacts from auth actions file --- app/actions/auth.ts | 287 ++++++++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 144 deletions(-) diff --git a/app/actions/auth.ts b/app/actions/auth.ts index 2aef7e3..fca3de3 100644 --- a/app/actions/auth.ts +++ b/app/actions/auth.ts @@ -1,144 +1,143 @@ - 1|'use server' - 2| - 3|import { cookies } from 'next/headers' - 4| - 5|const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081' - 6| - 7|interface AuthResponse { - 8| access_token: string - 9| refresh_token: string - 10| id_token: string - 11| expires_in: number - 12|} - 13| - 14|interface UserPayload { - 15| sub: string - 16| email?: string - 17| totp_enabled?: boolean - 18|} - 19| - 20|export async function exchangeAuthCode(code: string, codeVerifier: string, redirectUri: string) { - 21| try { - 22| const res = await fetch(`${AUTH_API_URL}/oauth/token`, { - 23| method: 'POST', - 24| headers: { - 25| 'Content-Type': 'application/json', - 26| }, - 27| body: JSON.stringify({ - 28| grant_type: 'authorization_code', - 29| code, - 30| client_id: 'analytics-app', - 31| redirect_uri: redirectUri, - 32| code_verifier: codeVerifier, - 33| }), - 34| }) - 35| - 36| if (!res.ok) { - 37| const data = await res.json() - 38| throw new Error(data.error || 'Failed to exchange token') - 39| } - 40| - 41| const data: AuthResponse = await res.json() - 42| - 43| // * Decode payload (without verification, we trust the direct channel to Auth Server) - 44| const payloadPart = data.access_token.split('.')[1] - 45| const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) - 46| - 47| // * Set Cookies - 48| const cookieStore = await cookies() - 49| - 50| // * Access Token - 51| cookieStore.set('access_token', data.access_token, { - 52| httpOnly: true, - 53| secure: process.env.NODE_ENV === 'production', - 54| sameSite: 'lax', - 55| path: '/', - 56| maxAge: 60 * 15 // 15 minutes (short lived) - 57| }) - 58| - 59| // * Refresh Token (Long lived) - 60| cookieStore.set('refresh_token', data.refresh_token, { - 61| httpOnly: true, - 62| secure: process.env.NODE_ENV === 'production', - 63| sameSite: 'lax', - 64| path: '/', - 65| maxAge: 60 * 60 * 24 * 30 // 30 days - 66| }) - 67| - 68| return { - 69| success: true, - 70| user: { - 71| id: payload.sub, - 72| email: payload.email || 'user@ciphera.net', - 73| totp_enabled: payload.totp_enabled || false - 74| } - 75| } - 76| - 77| } catch (error: any) { - 78| console.error('Auth Exchange Error:', error) - 79| return { success: false, error: error.message } - 80| } - 81|} - 82| - 83|export async function setSessionAction(accessToken: string, refreshToken: string) { - 84| try { - 85| const payloadPart = accessToken.split('.')[1] - 86| const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) - 87| - 88| const cookieStore = await cookies() - 89| - 90| cookieStore.set('access_token', accessToken, { - 91| httpOnly: true, - 92| secure: process.env.NODE_ENV === 'production', - 93| sameSite: 'lax', - 94| path: '/', - 95| maxAge: 60 * 15 - 96| }) - 97| - 98| cookieStore.set('refresh_token', refreshToken, { - 99| httpOnly: true, - 100| secure: process.env.NODE_ENV === 'production', - 101| sameSite: 'lax', - 102| path: '/', - 103| maxAge: 60 * 60 * 24 * 30 - 104| }) - 105| - 106| return { - 107| success: true, - 108| user: { - 109| id: payload.sub, - 110| email: payload.email || 'user@ciphera.net', - 111| totp_enabled: payload.totp_enabled || false - 112| } - 113| } - 114| } catch (e) { - 115| return { success: false, error: 'Invalid token' } - 116| } - 117|} - 118| - 119|export async function logoutAction() { - 120| const cookieStore = await cookies() - 121| cookieStore.delete('access_token') - 122| cookieStore.delete('refresh_token') - 123| return { success: true } - 124|} - 125| - 126|export async function getSessionAction() { - 127| const cookieStore = await cookies() - 128| const token = cookieStore.get('access_token') - 129| - 130| if (!token) return null - 131| - 132| try { - 133| const payloadPart = token.value.split('.')[1] - 134| const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) - 135| return { - 136| id: payload.sub, - 137| email: payload.email || 'user@ciphera.net', - 138| totp_enabled: payload.totp_enabled || false - 139| } - 140| } catch { - 141| return null - 142| } - 143|} - 144| \ No newline at end of file +'use server' + +import { cookies } from 'next/headers' + +const AUTH_API_URL = process.env.NEXT_PUBLIC_AUTH_API_URL || process.env.NEXT_PUBLIC_AUTH_URL || 'http://localhost:8081' + +interface AuthResponse { + access_token: string + refresh_token: string + id_token: string + expires_in: number +} + +interface UserPayload { + sub: string + email?: string + totp_enabled?: boolean +} + +export async function exchangeAuthCode(code: string, codeVerifier: string, redirectUri: string) { + try { + const res = await fetch(`${AUTH_API_URL}/oauth/token`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + grant_type: 'authorization_code', + code, + client_id: 'analytics-app', + redirect_uri: redirectUri, + code_verifier: codeVerifier, + }), + }) + + if (!res.ok) { + const data = await res.json() + throw new Error(data.error || 'Failed to exchange token') + } + + const data: AuthResponse = await res.json() + + // * Decode payload (without verification, we trust the direct channel to Auth Server) + const payloadPart = data.access_token.split('.')[1] + const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) + + // * Set Cookies + const cookieStore = await cookies() + + // * Access Token + cookieStore.set('access_token', data.access_token, { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + maxAge: 60 * 15 // 15 minutes (short lived) + }) + + // * Refresh Token (Long lived) + cookieStore.set('refresh_token', data.refresh_token, { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + maxAge: 60 * 60 * 24 * 30 // 30 days + }) + + return { + success: true, + user: { + id: payload.sub, + email: payload.email || 'user@ciphera.net', + totp_enabled: payload.totp_enabled || false + } + } + + } catch (error: any) { + console.error('Auth Exchange Error:', error) + return { success: false, error: error.message } + } +} + +export async function setSessionAction(accessToken: string, refreshToken: string) { + try { + const payloadPart = accessToken.split('.')[1] + const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) + + const cookieStore = await cookies() + + cookieStore.set('access_token', accessToken, { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + maxAge: 60 * 15 + }) + + cookieStore.set('refresh_token', refreshToken, { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + maxAge: 60 * 60 * 24 * 30 + }) + + return { + success: true, + user: { + id: payload.sub, + email: payload.email || 'user@ciphera.net', + totp_enabled: payload.totp_enabled || false + } + } + } catch (e) { + return { success: false, error: 'Invalid token' } + } +} + +export async function logoutAction() { + const cookieStore = await cookies() + cookieStore.delete('access_token') + cookieStore.delete('refresh_token') + return { success: true } +} + +export async function getSessionAction() { + const cookieStore = await cookies() + const token = cookieStore.get('access_token') + + if (!token) return null + + try { + const payloadPart = token.value.split('.')[1] + const payload: UserPayload = JSON.parse(Buffer.from(payloadPart, 'base64').toString()) + return { + id: payload.sub, + email: payload.email || 'user@ciphera.net', + totp_enabled: payload.totp_enabled || false + } + } catch { + return null + } +}