Skip to content

Commit 3e366c0

Browse files
committed
allow token generation for trusted domain
1 parent 0447938 commit 3e366c0

4 files changed

Lines changed: 86 additions & 4 deletions

File tree

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ NEXTAUTH_SECRET='your_nextauth_secret_here'
1919
JWT_AUDIENCE='sdg-innovation-commons'
2020
JWT_ISSUER='sdg-innovation-commons'
2121

22+
# Trusted domains for automatic authentication (comma-separated)
23+
# These domains will automatically get API access with rights level 3
24+
TRUSTED_DOMAINS='https://undp-accelerator-labs.github.io'
25+
2226
# Authentication Feature Flags
2327
# Set to 'false' to disable UNDP SSO (Single Sign-On) login tab
2428
NEXT_PUBLIC_ENABLE_UNDP_SSO='true'

app/lib/services/auth.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,32 @@ export async function getSession(): Promise<SessionInfo | null> {
5151
if (isApiAuthenticated) {
5252
const uuid = headersList.get('x-api-user-uuid');
5353
const email = headersList.get('x-api-user-email') || '';
54+
const name = headersList.get('x-api-user-name') || '';
5455
const rights = parseInt(headersList.get('x-api-user-rights') || '0', 10);
56+
const isAutoGenerated = headersList.get('x-api-auto-generated') === 'true';
57+
const trustedDomain = headersList.get('x-api-trusted-domain');
5558

5659
if (!uuid) return null;
5760

58-
// Fetch full user data from database for API token users
61+
// If this is an auto-generated trusted domain token, return session without DB lookup
62+
if (isAutoGenerated && trustedDomain) {
63+
return {
64+
uuid: uuid,
65+
email: email,
66+
name: name,
67+
rights: rights,
68+
iso3: '',
69+
language: 'en',
70+
bureau: '',
71+
collaborators: [],
72+
pinboards: [],
73+
is_trusted: true,
74+
trusted_domain: trustedDomain,
75+
loginTime: new Date().toISOString(),
76+
};
77+
}
78+
79+
// Fetch full user data from database for regular API token users
5980
try {
6081
const { query } = await import('../db');
6182

@@ -94,7 +115,7 @@ export async function getSession(): Promise<SessionInfo | null> {
94115
return {
95116
uuid: user.uuid,
96117
email: user.email || email,
97-
name: user.name || '',
118+
name: user.name || name,
98119
rights: user.rights || rights,
99120
iso3: user.iso3 || '',
100121
language: user.language || 'en',

app/lib/types/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface SessionInfo {
1717
collaborators?: string[];
1818
pinboards?: number[];
1919
is_trusted?: boolean;
20+
trusted_domain?: string;
2021
loginTime: string;
2122
}
2223

proxy.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
22
import { auth } from "@/auth";
33
import jwt from "jsonwebtoken";
44

5-
const { APP_SECRET } = process.env;
5+
const { APP_SECRET, TRUSTED_DOMAINS } = process.env;
66

77
const cspLinks = [
88
"'self'",
@@ -45,8 +45,64 @@ export async function proxy(request: NextRequest) {
4545
];
4646
const isPublicApiRoute = publicApiRoutes.some(route => currentPath.startsWith(route));
4747

48-
// If it's an API route (not public), check for Bearer token if provided
48+
// If it's an API route (not public), check for trusted domains first, then Bearer token
4949
if (isApiRoute && !isPublicApiRoute) {
50+
// Check if request is from a trusted domain
51+
const origin = request.headers.get('origin');
52+
const referer = request.headers.get('referer');
53+
54+
if (TRUSTED_DOMAINS) {
55+
const trustedDomains = TRUSTED_DOMAINS.split(',').map(d => d.trim());
56+
const requestDomain = origin || (referer ? new URL(referer).origin : null);
57+
58+
if (requestDomain && trustedDomains.includes(requestDomain)) {
59+
60+
// Generate automatic API token for trusted domain with rights level 3
61+
try {
62+
const trustedToken = jwt.sign(
63+
{
64+
type: 'api_access',
65+
uuid: 'trusted-domain-user',
66+
email: 'trusted@domain.auto',
67+
rights: 3,
68+
name: 'Trusted Domain User',
69+
trusted_domain: requestDomain,
70+
iat: Math.floor(Date.now() / 1000),
71+
},
72+
APP_SECRET || 'fallback-secret-key',
73+
{
74+
expiresIn: '1h', // Short-lived token for security
75+
audience: 'sdg-innovation-commons',
76+
issuer: 'sdg-innovation-commons',
77+
}
78+
);
79+
80+
// Add trusted user info to headers for API routes to use
81+
const requestHeaders = new Headers(request.headers);
82+
requestHeaders.set('x-api-user-uuid', 'trusted-domain-user');
83+
requestHeaders.set('x-api-user-email', 'trusted@domain.auto');
84+
requestHeaders.set('x-api-user-rights', '3');
85+
requestHeaders.set('x-api-user-name', 'Trusted Domain User');
86+
requestHeaders.set('x-api-authenticated', 'true');
87+
requestHeaders.set('x-api-trusted-domain', requestDomain);
88+
requestHeaders.set('x-api-auto-generated', 'true');
89+
90+
console.log(`✅ Auto-generated token for trusted domain: ${requestDomain} with rights level 3`);
91+
92+
const response = NextResponse.next({
93+
request: {
94+
headers: requestHeaders,
95+
},
96+
});
97+
98+
return response;
99+
} catch (error) {
100+
console.error('Error generating trusted domain token:', error);
101+
// Continue to regular token validation if auto-generation fails
102+
}
103+
}
104+
}
105+
50106
const authHeader = request.headers.get('authorization');
51107

52108
// Check for token in multiple places: header, query params, or body

0 commit comments

Comments
 (0)