Overview
The /reauthenticate endpoint verifies the user’s identity for sensitive operations that require additional security confirmation. This endpoint is typically used before allowing users to perform critical actions like changing passwords, updating payment methods, or accessing sensitive data.
This endpoint requires a valid JWT token in the Authorization header.
Request
curl -X GET "https://auth-api.yourdomain.com/reauthenticate" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json"
Response
200 - Success
401 - Unauthorized
403 - Forbidden
{
"message" : "Reauthentication successful" ,
"timestamp" : "2023-12-01T10:30:00Z" ,
"valid_until" : "2023-12-01T10:45:00Z"
}
Response Fields
Field Type Description messagestring Success message timestampstring Current timestamp valid_untilstring When the reauthentication expires (typically 15 minutes)
Implementation Examples
React Hook for Reauthentication
import { useState } from 'react' ;
import { useAuth } from './useAuth' ;
export function useReauthentication () {
const [ isReauthenticated , setIsReauthenticated ] = useState ( false );
const [ loading , setLoading ] = useState ( false );
const [ error , setError ] = useState ( null );
const { accessToken } = useAuth ();
const reauthenticate = async () => {
setLoading ( true );
setError ( null );
try {
const response = await fetch ( '/api/auth/reauthenticate' , {
method: 'GET' ,
headers: {
'Authorization' : `Bearer ${ accessToken } ` ,
'Content-Type' : 'application/json'
}
});
if ( ! response . ok ) {
throw new Error ( 'Reauthentication failed' );
}
const result = await response . json ();
setIsReauthenticated ( true );
// Auto-expire reauthentication after 15 minutes
setTimeout (() => {
setIsReauthenticated ( false );
}, 15 * 60 * 1000 );
return result ;
} catch ( err ) {
setError ( err . message );
setIsReauthenticated ( false );
throw err ;
} finally {
setLoading ( false );
}
};
const clearReauthentication = () => {
setIsReauthenticated ( false );
setError ( null );
};
return {
isReauthenticated ,
reauthenticate ,
clearReauthentication ,
loading ,
error
};
}
// Usage in component
function SensitiveOperation () {
const { isReauthenticated , reauthenticate , loading } = useReauthentication ();
const [ showReauthPrompt , setShowReauthPrompt ] = useState ( false );
const handleSensitiveAction = async () => {
if ( ! isReauthenticated ) {
setShowReauthPrompt ( true );
return ;
}
// Proceed with sensitive operation
await performSensitiveOperation ();
};
const handleReauthenticate = async () => {
try {
await reauthenticate ();
setShowReauthPrompt ( false );
// Now proceed with the sensitive operation
await performSensitiveOperation ();
} catch ( error ) {
console . error ( 'Reauthentication failed:' , error );
}
};
if ( showReauthPrompt ) {
return (
< div className = "reauthentication-prompt" >
< h3 > Security Verification Required </ h3 >
< p > This action requires additional verification for your security. </ p >
< button
onClick = { handleReauthenticate }
disabled = { loading }
>
{ loading ? 'Verifying...' : 'Verify Identity' }
</ button >
< button onClick = { () => setShowReauthPrompt ( false ) } >
Cancel
</ button >
</ div >
);
}
return (
< button onClick = { handleSensitiveAction } >
Perform Sensitive Action
</ button >
);
}
Protected Route Component
import { useEffect , useState } from 'react' ;
import { useReauthentication } from './useReauthentication' ;
function ProtectedSensitiveRoute ({ children }) {
const { isReauthenticated , reauthenticate , loading } = useReauthentication ();
const [ showReauthForm , setShowReauthForm ] = useState ( false );
useEffect (() => {
// Check if reauthentication is needed when component mounts
if ( ! isReauthenticated ) {
setShowReauthForm ( true );
}
}, [ isReauthenticated ]);
const handleReauthenticate = async () => {
try {
await reauthenticate ();
setShowReauthForm ( false );
} catch ( error ) {
console . error ( 'Reauthentication failed:' , error );
}
};
if ( showReauthForm ) {
return (
< div className = "reauthentication-gate" >
< div className = "reauthentication-card" >
< h2 > Security Verification </ h2 >
< p >
For your security, please verify your identity to access this section.
</ p >
< button
onClick = { handleReauthenticate }
disabled = { loading }
className = "btn-primary"
>
{ loading ? 'Verifying...' : 'Verify Identity' }
</ button >
</ div >
</ div >
);
}
return children ;
}
// Usage
function App () {
return (
< Routes >
< Route path = "/settings" element = {
< ProtectedSensitiveRoute >
< UserSettings />
</ ProtectedSensitiveRoute >
} />
< Route path = "/billing" element = {
< ProtectedSensitiveRoute >
< BillingSettings />
</ ProtectedSensitiveRoute >
} />
</ Routes >
);
}
Node.js Middleware
const jwt = require ( 'jsonwebtoken' );
// Middleware to check if reauthentication is required
function requireReauthentication ( maxAge = 15 * 60 * 1000 ) { // 15 minutes default
return async ( req , res , next ) => {
try {
const token = req . headers . authorization ?. replace ( 'Bearer ' , '' );
if ( ! token ) {
return res . status ( 401 ). json ({
code: 401 ,
msg: 'No token provided'
});
}
// Decode token without verification to check timestamp
const decoded = jwt . decode ( token );
if ( ! decoded ) {
return res . status ( 401 ). json ({
code: 401 ,
msg: 'Invalid token format'
});
}
const tokenAge = Date . now () - ( decoded . iat * 1000 );
if ( tokenAge > maxAge ) {
return res . status ( 403 ). json ({
code: 403 ,
msg: 'Reauthentication required' ,
details: 'Token is too old for sensitive operations'
});
}
// Check if user has recently reauthenticated
const reauthKey = `reauth: ${ decoded . sub } ` ;
const reauthTimestamp = await redis . get ( reauthKey );
if ( ! reauthTimestamp || ( Date . now () - parseInt ( reauthTimestamp )) > maxAge ) {
return res . status ( 403 ). json ({
code: 403 ,
msg: 'Reauthentication required' ,
details: 'Recent identity verification required'
});
}
next ();
} catch ( error ) {
res . status ( 500 ). json ({
code: 500 ,
msg: 'Internal server error'
});
}
};
}
// Reauthentication endpoint handler
app . get ( '/reauthenticate' , authenticateToken , async ( req , res ) => {
try {
const userId = req . user . sub ;
const now = Date . now ();
// Store reauthentication timestamp
const reauthKey = `reauth: ${ userId } ` ;
await redis . setex ( reauthKey , 15 * 60 , now . toString ()); // 15 minutes TTL
res . json ({
message: 'Reauthentication successful' ,
timestamp: new Date ( now ). toISOString (),
valid_until: new Date ( now + 15 * 60 * 1000 ). toISOString ()
});
} catch ( error ) {
res . status ( 500 ). json ({
code: 500 ,
msg: 'Internal server error'
});
}
});
// Usage on sensitive routes
app . put ( '/user/password' ,
authenticateToken ,
requireReauthentication ( 10 * 60 * 1000 ), // 10 minutes for password change
async ( req , res ) => {
// Handle password change
res . json ({ message: 'Password updated successfully' });
}
);
app . delete ( '/user/account' ,
authenticateToken ,
requireReauthentication ( 5 * 60 * 1000 ), // 5 minutes for account deletion
async ( req , res ) => {
// Handle account deletion
res . json ({ message: 'Account deleted successfully' });
}
);
Use Cases
Sensitive Operations
Require reauthentication before:
Changing passwords or email addresses
Updating payment methods
Deleting accounts or data
Accessing financial information
Modifying security settings
Time-Based Security
Short-lived verification : 5-15 minutes for critical operations
Session-based : Require reauthentication once per session for sensitive areas
Operation-specific : Different timeouts for different sensitivity levels
Progressive Security
Low sensitivity : No reauthentication required
Medium sensitivity : Reauthentication within last 15 minutes
High sensitivity : Reauthentication within last 5 minutes
Critical operations : Fresh reauthentication required
Security Considerations
Token Age : Check both JWT iat (issued at) and recent reauthentication timestamp
Secure Storage : Store reauthentication state securely (Redis, encrypted cookies)
Time Limits : Use appropriate time limits based on operation sensitivity
User Experience : Balance security with usability
Audit Logging : Log reauthentication attempts and sensitive operations
Rate Limiting
Endpoint : 10 requests per 5 minutes per user
Purpose : Prevent abuse while allowing legitimate use
Headers : Standard rate limiting headers included in response
User Profile - May require reauthentication for sensitive data
Update Profile - Requires reauthentication for security fields
Logout - Alternative to reauthentication for security
Testing
// Jest test example
describe ( 'Reauthentication' , () => {
test ( 'should succeed with valid token' , async () => {
const response = await request ( app )
. get ( '/reauthenticate' )
. set ( 'Authorization' , `Bearer ${ validToken } ` );
expect ( response . status ). toBe ( 200 );
expect ( response . body ). toHaveProperty ( 'message' );
expect ( response . body ). toHaveProperty ( 'valid_until' );
});
test ( 'should fail without token' , async () => {
const response = await request ( app )
. get ( '/reauthenticate' );
expect ( response . status ). toBe ( 401 );
expect ( response . body . msg ). toContain ( 'token' );
});
test ( 'should require reauthentication for old tokens' , async () => {
const oldToken = generateToken ({ iat: Math . floor ( Date . now () / 1000 ) - 3600 }); // 1 hour old
const response = await request ( app )
. put ( '/user/password' )
. set ( 'Authorization' , `Bearer ${ oldToken } ` )
. send ({ password: 'newpassword123' });
expect ( response . status ). toBe ( 403 );
expect ( response . body . msg ). toContain ( 'Reauthentication required' );
});
});