@@ -8,6 +8,10 @@ import {
88 getAuth0LogoutUrl ,
99 getAuth0UserCredential ,
1010} from "../services/auth0.service" ;
11+ import {
12+ completeLocalAuth0TokenExchange ,
13+ isLocalAuth ,
14+ } from "../services/auth0-local.service" ;
1115import {
1216 createAuthToken ,
1317 createSdfAuthToken ,
@@ -49,6 +53,23 @@ const parseCliRedirectPort = (port: string[] | string): number => {
4953} ;
5054
5155router . get ( "/auth/login" , async ( ctx ) => {
56+ // LOCAL AUTH MODE: bypass Auth0 entirely for local development
57+ if ( isLocalAuth ( ) ) {
58+ // eslint-disable-next-line no-console
59+ console . log ( JSON . stringify ( {
60+ timestamp : new Date ( ) . toISOString ( ) ,
61+ level : "info" ,
62+ type : "local-auth" ,
63+ action : "login_redirect" ,
64+ message : "🔧 LOCAL AUTH MODE: Redirecting to local login - NO Auth0 calls" ,
65+ } ) ) ;
66+
67+ // Redirect directly to local login success (auto-authenticate)
68+ ctx . redirect ( `${ process . env . AUTH_PORTAL_URL } /login-success?local=true` ) ;
69+ return ;
70+ }
71+
72+ // PRODUCTION MODE: Normal Auth0 OAuth flow
5273 // passing in cli_redir=PORT_NO will begin the auth flow for the si cli
5374 const cliRedirParam = ctx . request . query . cli_redir ;
5475 const cliRedirect = cliRedirParam
@@ -178,6 +199,67 @@ router.get("/auth/login-callback", async (ctx) => {
178199 }
179200} ) ;
180201
202+ /**
203+ * LOCAL AUTH MODE ONLY
204+ * Simple login endpoint that bypasses Auth0 entirely
205+ * Creates/updates local user and returns session token
206+ */
207+ router . post ( "/auth/local-login" , async ( ctx ) => {
208+ if ( ! isLocalAuth ( ) ) {
209+ throw new ApiError ( "Forbidden" , "LocalAuthDisabled" , "Local auth mode is not enabled" ) ;
210+ }
211+
212+ // eslint-disable-next-line no-console
213+ console . log ( JSON . stringify ( {
214+ timestamp : new Date ( ) . toISOString ( ) ,
215+ level : "info" ,
216+ type : "local-auth" ,
217+ action : "local_login" ,
218+ message : "🔧 LOCAL AUTH MODE: Processing local login - NO Auth0 interaction" ,
219+ } ) ) ;
220+
221+ const reqBody = validate (
222+ ctx . request . body ,
223+ z . object ( {
224+ email : z . string ( ) . email ( ) . optional ( ) ,
225+ } ) ,
226+ ) ;
227+
228+ // Use local mock Auth0 profile
229+ const { profile } = await completeLocalAuth0TokenExchange ( reqBody . email ) ;
230+ const user = await createOrUpdateUserFromAuth0Details ( profile ) ;
231+
232+ // eslint-disable-next-line no-console
233+ console . log ( JSON . stringify ( {
234+ timestamp : new Date ( ) . toISOString ( ) ,
235+ level : "info" ,
236+ type : "local-auth" ,
237+ action : "user_authenticated" ,
238+ userId : user . id ,
239+ email : user . email ,
240+ message : "🔧 LOCAL AUTH MODE: User authenticated locally" ,
241+ } ) ) ;
242+
243+ // Create session token for auth-api communication
244+ const siToken = createAuthToken ( user . id ) ;
245+
246+ ctx . cookies . set ( SI_COOKIE_NAME , siToken , {
247+ httpOnly : true ,
248+ secure : false , // Local development doesn't use HTTPS
249+ } ) ;
250+
251+ ctx . body = {
252+ user : {
253+ id : user . id ,
254+ email : user . email ,
255+ firstName : user . firstName ,
256+ lastName : user . lastName ,
257+ nickname : user . nickname ,
258+ } ,
259+ token : siToken ,
260+ } ;
261+ } ) ;
262+
181263router . get ( "/auth/cli-auth-api-token" , async ( ctx ) => {
182264 const nonce = ctx . request . query . nonce ;
183265 if ( ! nonce ) {
0 commit comments