@@ -70,40 +70,27 @@ export async function requestMagicLink(req: Request, res: Response) {
7070}
7171
7272export async function verifyMagicLink ( req : Request , res : Response ) {
73- const parse = MagicLinkVerifyQuerySchema . safeParse ( req . query ) ;
73+ const { token } = req . params ;
7474
75- if ( ! parse . success ) {
76- return res . redirect ( '/login?error=invalid' ) ;
75+ if ( ! token ) {
76+ return res . status ( 400 ) . json ( { message : 'Missing verification token' } ) ;
7777 }
78-
79- const { token } = parse . data ;
8078 const tokenHash = hashSha256 ( token ) ;
8179
8280 const record = await MagicLinkToken . findOne ( {
8381 where : { token_hash : tokenHash } ,
8482 } ) ;
8583
8684 if ( ! record ) {
87- return res . redirect ( '/login?error=invalid' ) ;
85+ return res . status ( 400 ) . json ( { message : 'Invalid verification token' } ) ;
8886 }
8987
9088 if ( record . used_at ) {
91- return res . redirect ( '/login?error=used' ) ;
89+ return res . status ( 400 ) . json ( { message : 'Invalid verification token' } ) ;
9290 }
9391
9492 if ( record . expires_at < new Date ( ) ) {
95- return res . redirect ( '/login?error=expired' ) ;
96- }
97-
98- // Device binding check
99- const { ip_hash, user_agent_hash } = hashDeviceFingerprint ( req . ip , req . headers [ 'user-agent' ] ) ;
100-
101- if ( record . ip_hash && record . ip_hash !== ip_hash ) {
102- return res . redirect ( '/login?error=device_mismatch' ) ;
103- }
104-
105- if ( record . user_agent_hash && record . user_agent_hash !== user_agent_hash ) {
106- return res . redirect ( '/login?error=device_mismatch' ) ;
93+ return res . status ( 400 ) . json ( { message : 'Invalid verification token' } ) ;
10794 }
10895
10996 // Atomic consume
@@ -118,7 +105,7 @@ export async function verifyMagicLink(req: Request, res: Response) {
118105 ) ;
119106
120107 if ( ! updated ) {
121- return res . redirect ( '/login?error=invalid' ) ;
108+ return res . status ( 500 ) . json ( { message : 'Failed to use token' } ) ;
122109 }
123110
124111 await AuthEventService . log ( {
@@ -127,7 +114,18 @@ export async function verifyMagicLink(req: Request, res: Response) {
127114 req,
128115 } ) ;
129116
130- return res . redirect ( record . redirect_url || '/' ) ;
117+ // Device binding check
118+ const { ip_hash, user_agent_hash } = hashDeviceFingerprint ( req . ip , req . headers [ 'user-agent' ] ) ;
119+
120+ if ( record . ip_hash && record . ip_hash !== ip_hash ) {
121+ return res . status ( 200 ) . json ( { message : 'Success' } ) ;
122+ }
123+
124+ if ( record . user_agent_hash && record . user_agent_hash !== user_agent_hash ) {
125+ return res . status ( 200 ) . json ( { message : 'Success' } ) ;
126+ }
127+
128+ return res . status ( 200 ) . json ( { message : 'Success' } ) ;
131129}
132130
133131export async function pollMagicLinkConfirmation ( req : Request , res : Response ) {
0 commit comments