(
request: NextRequest,
options: { requireWorkflowId?: boolean } = {}
)
| 174 | * For internal JWT calls, requires workflowId to determine user context |
| 175 | */ |
| 176 | export async function checkHybridAuth( |
| 177 | request: NextRequest, |
| 178 | options: { requireWorkflowId?: boolean } = {} |
| 179 | ): Promise<AuthResult> { |
| 180 | try { |
| 181 | // 1. Check for internal JWT token first |
| 182 | const authHeader = request.headers.get('authorization') |
| 183 | if (authHeader?.startsWith('Bearer ')) { |
| 184 | const token = authHeader.split(' ')[1] |
| 185 | const verification = await verifyInternalToken(token) |
| 186 | |
| 187 | if (verification.valid) { |
| 188 | return resolveUserFromJwt(verification.userId || null, options) |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | // 2. Try session auth (for web UI) |
| 193 | const session = await getSession() |
| 194 | if (session?.user?.id) { |
| 195 | return { |
| 196 | success: true, |
| 197 | userId: session.user.id, |
| 198 | userName: session.user.name, |
| 199 | userEmail: session.user.email, |
| 200 | authType: AuthType.SESSION, |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | // 3. Try API key auth (X-API-Key header only) |
| 205 | const apiKeyHeader = request.headers.get('x-api-key') |
| 206 | if (apiKeyHeader) { |
| 207 | const result = await authenticateApiKeyFromHeader(apiKeyHeader) |
| 208 | if (result.success) { |
| 209 | await updateApiKeyLastUsed(result.keyId!) |
| 210 | return { |
| 211 | success: true, |
| 212 | userId: result.userId!, |
| 213 | workspaceId: result.workspaceId, |
| 214 | authType: AuthType.API_KEY, |
| 215 | apiKeyType: result.keyType, |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | return { |
| 220 | success: false, |
| 221 | error: 'Invalid API key', |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | // No authentication found |
| 226 | return { |
| 227 | success: false, |
| 228 | error: 'Unauthorized', |
| 229 | } |
| 230 | } catch (error) { |
| 231 | logger.error('Error in hybrid authentication:', error) |
| 232 | return { |
| 233 | success: false, |
no test coverage detected