MotorSignal-App/website/app/api/ops/auth/session/route.ts

120 lines
3.8 KiB
TypeScript

import { cookies } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';
function getSafeRedirectUrl(targetPath: string, request: NextRequest): URL {
const forwardedHost = request.headers.get('x-forwarded-host')?.split(',')[0].trim()
?? request.headers.get('host')
?? 'motorsignal.app';
const forwardedProto = request.headers.get('x-forwarded-proto')?.split(',')[0].trim()
?? (process.env.NODE_ENV === 'production' ? 'https' : 'http');
return new URL(targetPath, `${forwardedProto}://${forwardedHost}`);
}
export async function GET(request: NextRequest) {
const cookieStore = await cookies();
const riderToken = cookieStore.get('motorsignal_access_token')?.value;
if (!riderToken) {
return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request));
}
const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app';
try {
const upstream = await fetch(`${baseUrl}/api/v1/ops/session/bootstrap`, {
method: 'POST',
headers: {
authorization: `Bearer ${riderToken}`,
accept: 'application/json',
},
cache: 'no-store',
});
if (upstream.ok) {
const data = (await upstream.json()) as { ops_token?: string };
const opsToken = data.ops_token;
if (opsToken) {
const redirectUrl = getSafeRedirectUrl('/admin', request);
const response = NextResponse.redirect(redirectUrl);
const opsCookieOptions = {
httpOnly: true,
secure: true,
sameSite: 'lax' as const,
path: '/',
maxAge: 60 * 60 * 8,
};
response.cookies.set('__Host-motorsignal_ops', opsToken, opsCookieOptions);
response.cookies.set('motorsignal_ops', opsToken, {
...opsCookieOptions,
secure: process.env.NODE_ENV === 'production',
});
return response;
}
}
if (upstream.status === 403) {
return NextResponse.redirect(getSafeRedirectUrl('/admin?error=forbidden', request));
}
return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request));
} catch {
return NextResponse.redirect(getSafeRedirectUrl('/login?returnTo=/admin', request));
}
}
export async function POST(request: NextRequest) {
const cookieStore = await cookies();
const riderToken = cookieStore.get('motorsignal_access_token')?.value;
if (!riderToken) {
return NextResponse.json({ detail: 'Rider authentication required.' }, { status: 401 });
}
const baseUrl = process.env.MOTORSIGNAL_API_BASE_URL ?? 'https://api.motorsignal.app';
try {
const upstream = await fetch(`${baseUrl}/api/v1/ops/session/bootstrap`, {
method: 'POST',
headers: {
authorization: `Bearer ${riderToken}`,
accept: 'application/json',
},
cache: 'no-store',
});
if (!upstream.ok) {
const err = await upstream.json().catch(() => ({}));
return NextResponse.json(err, { status: upstream.status });
}
const data = (await upstream.json()) as { ops_token?: string };
const opsToken = data.ops_token;
if (!opsToken) {
return NextResponse.json({ detail: 'Failed to issue operations token.' }, { status: 500 });
}
const response = NextResponse.json({ success: true }, { status: 200 });
const opsCookieOptions = {
httpOnly: true,
secure: true,
sameSite: 'lax' as const,
path: '/',
maxAge: 60 * 60 * 8,
};
response.cookies.set('__Host-motorsignal_ops', opsToken, opsCookieOptions);
response.cookies.set('motorsignal_ops', opsToken, {
...opsCookieOptions,
secure: process.env.NODE_ENV === 'production',
});
return response;
} catch {
return NextResponse.json({ detail: 'Operations bootstrap unavailable.' }, { status: 503 });
}
}