Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions rafts/frontend/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ const securityHeaders = [
]

const nextConfig: NextConfig = {
// Add these for CANFAR compatibility
// Use the BASE_PATH from environment if available
basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || '',
// CANFAR deployment: app always runs at /rafts
basePath: '/rafts',
assetPrefix: '/rafts',
// Trust the proxy headers
poweredByHeader: false,

Expand Down
11 changes: 5 additions & 6 deletions rafts/frontend/src/app/api/auth/sso/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,22 @@
************************************************************************
*/

import { NextRequest, NextResponse } from 'next/server'
import { NextRequest } from 'next/server'
import { redirect } from 'next/navigation'
import { signIn } from '@/auth/cadc-auth/credentials'
import { parseCADCSSOCookie } from '@/auth/cadc-auth/parseCADCSSOCookie'

const basePath = process.env.NEXT_PUBLIC_BASE_PATH || ''

export async function GET(request: NextRequest) {
const cadcSso = request.cookies.get('CADC_SSO')?.value
const returnUrl = request.nextUrl.searchParams.get('returnUrl') || '/'

if (!cadcSso) {
return NextResponse.redirect(new URL(`${basePath}/login`, request.url))
redirect('/login')
}

const tokenInfo = parseCADCSSOCookie(cadcSso)
if (!tokenInfo) {
return NextResponse.redirect(new URL(`${basePath}/login`, request.url))
redirect('/login')
}

try {
Expand All @@ -99,6 +98,6 @@ export async function GET(request: NextRequest) {
}
// For other errors (e.g. CADC APIs rejected the token), fall through to login
console.error('[SSO] Auto-login failed:', error)
return NextResponse.redirect(new URL(`${basePath}/login`, request.url))
redirect('/login')
}
}
34 changes: 22 additions & 12 deletions rafts/frontend/src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,27 @@ const proxy = async (request: NextRequest) => {
return response
}

// SSO auto-login: if no session but CADC_SSO cookie is present, bootstrap a session.
// This runs on ALL pages (public and protected) so the user appears logged in everywhere.
// Skip paths that would cause loops (login, SSO endpoint itself).
const isStaleSession = session && (!session.user?.name || session.user.name.includes('undefined'))
const ssoSkipPaths = ['/login', '/login-required', '/api/auth']
const shouldSkipSso = ssoSkipPaths.some((p) => pathnameWithoutLocale.startsWith(p))

if ((!session || isStaleSession) && !shouldSkipSso) {
const cadcSso = request.cookies.get('CADC_SSO')?.value
const ssoToken = cadcSso ? parseCADCSSOCookie(cadcSso) : null

if (cadcSso && ssoToken) {
const returnPath = request.nextUrl.pathname || '/'
const ssoUrl = request.nextUrl.clone()
ssoUrl.pathname = '/api/auth/sso'
ssoUrl.searchParams.set('returnUrl', returnPath)
console.log('[Proxy] SSO redirect for', ssoToken.userID, 'from', returnPath)
return NextResponse.redirect(ssoUrl)
}
}

// Handle locale for non-API routes
const response = await intlMiddleware(request)

Expand All @@ -138,20 +159,9 @@ const proxy = async (request: NextRequest) => {
return response
}

// If not authenticated or session is stale (missing user name), try SSO or redirect to login
const isStaleSession = session && (!session.user?.name || session.user.name.includes('undefined'))
// Protected path without session — redirect to login
if (!session || isStaleSession) {
const returnPath = request.nextUrl.pathname || '/'

// Check for CADC_SSO cookie — auto-login if the user is already authenticated with CANFAR
const cadcSso = request.cookies.get('CADC_SSO')?.value
if (cadcSso && parseCADCSSOCookie(cadcSso)) {
const ssoUrl = request.nextUrl.clone()
ssoUrl.pathname = '/api/auth/sso'
ssoUrl.searchParams.set('returnUrl', returnPath)
return NextResponse.redirect(ssoUrl)
}

const loginRequiredUrl = request.nextUrl.clone()
loginRequiredUrl.pathname = '/login-required'
loginRequiredUrl.searchParams.set('returnUrl', returnPath)
Expand Down
Loading