NeahNew/app/api/auth/refresh-keycloak-session/route.ts

102 lines
3.3 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth/next';
import { authOptions } from '../options';
/**
* API endpoint to refresh Keycloak session cookies
* This ensures Keycloak session is active before loading iframe applications
*/
export async function GET(request: NextRequest) {
try {
// Check if user just logged out (prevent refresh after logout)
const logoutCookie = request.cookies.get('logout_in_progress');
if (logoutCookie?.value === 'true') {
console.log('Logout in progress, refusing to refresh session');
return NextResponse.json(
{
error: 'SessionInvalidated',
message: 'User is logging out. Please sign in again.'
},
{ status: 401 }
);
}
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session?.refreshToken) {
return NextResponse.json(
{ error: 'No active session' },
{ status: 401 }
);
}
// Refresh the Keycloak token to renew session cookies
// This will also refresh Keycloak session cookies in the browser
const keycloakIssuer = process.env.KEYCLOAK_ISSUER;
const clientId = process.env.KEYCLOAK_CLIENT_ID;
const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET;
if (!keycloakIssuer || !clientId || !clientSecret) {
return NextResponse.json(
{ error: 'Keycloak configuration missing' },
{ status: 500 }
);
}
// Use the refresh token to get new tokens
// This will also refresh Keycloak session cookies
const response = await fetch(`${keycloakIssuer}/protocol/openid-connect/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
grant_type: 'refresh_token',
refresh_token: session.refreshToken as string,
}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({}));
console.error('Failed to refresh Keycloak session:', error);
// If token is invalid (user logged out from Keycloak), return specific error
if (error.error === 'invalid_grant' ||
error.error_description?.includes('Token is not active') ||
error.error_description?.includes('Session not active')) {
return NextResponse.json(
{
error: 'SessionInvalidated',
message: 'Keycloak session was invalidated. Please sign in again.',
details: error
},
{ status: 401 }
);
}
return NextResponse.json(
{ error: 'Failed to refresh Keycloak session', details: error },
{ status: response.status }
);
}
const tokens = await response.json();
// Return success - the Keycloak session cookies are now refreshed
// The new tokens will be stored in NextAuth on next request
return NextResponse.json({
success: true,
message: 'Keycloak session refreshed',
});
} catch (error) {
console.error('Error refreshing Keycloak session:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}