@@ -6,6 +6,29 @@ import { eq } from "drizzle-orm";
66import { logger } from "../lib/logger" ;
77import type { ClerkUserData , ClerkJWTPayload , UserUpdateData , DatabaseError } from "../types" ;
88
9+ /**
10+ * Extract client IP from request headers (supports proxies like Cloudflare, ALB)
11+ */
12+ const getClientIp = ( c : Context ) : string => {
13+ // Check headers in order of priority
14+ const xForwardedFor = c . req . header ( "x-forwarded-for" ) ;
15+ if ( xForwardedFor ) {
16+ // First IP in the list is the original client
17+ return xForwardedFor . split ( "," ) [ 0 ] . trim ( ) ;
18+ }
19+
20+ const xRealIp = c . req . header ( "x-real-ip" ) ;
21+ if ( xRealIp ) return xRealIp ;
22+
23+ const cfConnectingIp = c . req . header ( "cf-connecting-ip" ) ;
24+ if ( cfConnectingIp ) return cfConnectingIp ;
25+
26+ // Fallback to socket remote address
27+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28+ const socket = ( c . req . raw as any ) . socket ;
29+ return socket ?. remoteAddress || "unknown" ;
30+ } ;
31+
932if ( ! process . env . CLERK_SECRET_KEY ) {
1033 throw new Error (
1134 "Missing Clerk Secret Key - Please add CLERK_SECRET_KEY to your environment variables"
@@ -49,6 +72,7 @@ const extractAndVerifyClerkToken = async (c: Context): Promise<ClerkUserData | n
4972} ;
5073
5174export const authMiddleware = async ( c : Context , next : Next ) => {
75+ const clientIp = getClientIp ( c ) ;
5276 const userData = await extractAndVerifyClerkToken ( c ) ;
5377
5478 if ( ! userData ) {
@@ -57,6 +81,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
5781 event_type : "auth_failure" ,
5882 reason : "Invalid or missing token" ,
5983 path : new URL ( c . req . url ) . pathname ,
84+ "http.client_ip" : clientIp ,
6085 } ) ;
6186 throw new HTTPException ( 401 , {
6287 message : "Authentication required" ,
@@ -77,6 +102,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
77102 error : error instanceof Error ? error . message : String ( error ) ,
78103 type : "database_error" ,
79104 event_type : "database_error" ,
105+ "http.client_ip" : clientIp ,
80106 } ,
81107 error instanceof Error ? error : undefined
82108 ) ;
@@ -110,6 +136,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
110136 logger . info ( "[AUTH] New user - fetching details from Clerk" , {
111137 userId : userData . id ,
112138 type : "auth_event" ,
139+ "http.client_ip" : clientIp ,
113140 } ) ;
114141
115142 // Fetch user details from Clerk API
@@ -126,6 +153,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
126153 logger . error ( "[AUTH] Cannot create user - no email found in Clerk" , {
127154 userId : userData . id ,
128155 type : "auth_error" ,
156+ "http.client_ip" : clientIp ,
129157 } ) ;
130158 throw new HTTPException ( 500 , {
131159 message : "User profile incomplete - email required" ,
@@ -160,6 +188,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
160188 email : newUser . email ,
161189 type : "auth_event" ,
162190 event_type : "user_created" ,
191+ "http.client_ip" : clientIp ,
163192 } ) ;
164193
165194 existingUser = newUser ;
@@ -169,6 +198,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
169198 logger . error ( "[AUTH] User not found in Clerk" , {
170199 userId : userData . id ,
171200 type : "auth_error" ,
201+ "http.client_ip" : clientIp ,
172202 } ) ;
173203 throw new HTTPException ( 401 , {
174204 message : "User account not found" ,
@@ -190,6 +220,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
190220 logger . error ( "[AUTH] User not found after race condition" , {
191221 userId : userData . id ,
192222 type : "database_error" ,
223+ "http.client_ip" : clientIp ,
193224 } ) ;
194225 throw new HTTPException ( 500 , {
195226 message : "Failed to create or find user profile" ,
@@ -202,6 +233,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
202233 userId : userData . id ,
203234 error : lookupError instanceof Error ? lookupError . message : String ( lookupError ) ,
204235 type : "database_error" ,
236+ "http.client_ip" : clientIp ,
205237 } ,
206238 lookupError instanceof Error ? lookupError : undefined
207239 ) ;
@@ -215,6 +247,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
215247 {
216248 userId : userData . id ,
217249 error : error instanceof Error ? error . message : String ( error ) ,
250+ "http.client_ip" : clientIp ,
218251 } ,
219252 error instanceof Error ? error : undefined
220253 ) ;
@@ -235,6 +268,7 @@ export const authMiddleware = async (c: Context, next: Next) => {
235268 event_type : "auth_success" ,
236269 "user.id" : userData . id ,
237270 "user.email" : existingUser . email ,
271+ "http.client_ip" : clientIp ,
238272 } ) ;
239273
240274 // User context available in Hono context
0 commit comments