This guide covers implementing session management using MoonKey’s REST API. Learn how to create, verify, extend, and delete user sessions in your backend application.
How session management works
Whenever a magic link, one-time passcode, or OAuth token is authenticated, MoonKey’s verify endpoints (VerifyOTP , and VerifyOAuthToken ) can issue a session token if a session_expires_in parameter is provided.
The session_expires_in parameter sets the duration of the session in minutes from the current time. This session will be associated with:
The authentication method used
The user who successfully authenticated
Device and browser information
All session endpoints require your secret API key and should only be used on your backend/server-side. NEVER expose your API key in client-side code.
Creating a session
During authentication
All verify endpoints support the session_expires_in parameter to create or extend a session:
cURL - Email OTP
cURL - Magic Link
cURL - OAuth
curl -X POST 'https://api.moonkey.fun/v1/auth/otps/verify' \
-H 'Authorization: Bearer sk_test_your_api_key' \
-H 'Content-Type: application/json' \
-d '{
"code": "123456",
"email": "user@example.com",
"session_expires_in": 10080
}'
Session duration constraints
Minimum duration: 5 minutes
Maximum duration: 366 days (527,040 minutes)
Default duration: 7 days (10,080 minutes)
The response will include both a session token and session JWT:
{
"session_token" : "vy9YGpubKjVn98cw1nT25Msj7jaIpHBinUfD45KLdAOgn9NqEuE4qGHOEchEG5Ue" ,
"session_jwt" : "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"user" : {
"id" : "user_abc123" ,
"email" : "user@example.com" ,
// ... other user fields
},
"session" : {
"id" : "session_xyz789" ,
"user_id" : "user_abc123" ,
"expires_at" : 1704067200 ,
"created_at" : 1703462400
}
}
Store the session_token or session_jwt on the client-side. The MoonKey SDK automatically handles this using IndexedDB.
Verifying sessions
Basic verification
Verify a session token to check if it’s still valid and retrieve the associated user:
curl -X POST 'https://api.moonkey.fun/v1/auth/sessions/verify' \
-H 'Authorization: Bearer sk_test_your_api_key' \
-H 'Content-Type: application/json' \
-d '{
"session_token": "vy9YGpubKjVn98cw1nT25Msj7jaIpHBinUfD45KLdAOgn9NqEuE4qGHOEchEG5Ue"
}'
Successful response
{
"session" : {
"id" : "session_xyz789" ,
"user_id" : "user_abc123" ,
"expires_at" : 1704067200 ,
"created_at" : 1703462400 ,
"device_info" : {
"user_agent" : "Mozilla/5.0..." ,
"ip_address" : "192.168.1.1"
}
},
"user" : {
"id" : "user_abc123" ,
"email" : "user@example.com" ,
// ... other user fields
}
}
Error response
When a session is invalid or expired:
{
"error" : {
"code" : "invalid_session" ,
"message" : "Session not found or has expired"
}
}
When a session is invalid, immediately delete the token from the client-side and return an unauthorized response to the user.
Extending sessions
You can extend an existing session’s duration using the session_expires_in parameter:
curl -X POST 'https://api.moonkey.fun/v1/auth/sessions/verify' \
-H 'Authorization: Bearer sk_test_your_api_key' \
-H 'Content-Type: application/json' \
-d '{
"session_token": "vy9YGpubKjVn98cw1nT25Msj7jaIpHBinUfD45KLdAOgn9NqEuE4qGHOEchEG5Ue",
"session_expires_in": 10080
}'
The extended session will now expire N minutes from the current time.
Common extension patterns
Use Case Duration (minutes) Duration (days) Short session 1,440 1 day Standard session 10,080 7 days Remember me 43,200 30 days Maximum duration 527,040 366 days
Listing active sessions
View all active sessions for a specific user using the ListSessions endpoint:
curl -X GET 'https://api.moonkey.fun/v1/auth/sessions/list?user_id=user_abc123' \
-H 'Authorization: Bearer sk_test_your_api_key'
Response
{
"sessions" : [
{
"id" : "session_xyz789" ,
"user_id" : "user_abc123" ,
"expires_at" : 1704067200 ,
"created_at" : 1703462400 ,
"device_info" : {
"user_agent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)..." ,
"ip_address" : "192.168.1.1"
}
},
{
"id" : "session_def456" ,
"user_id" : "user_abc123" ,
"expires_at" : 1704153600 ,
"created_at" : 1703548800 ,
"device_info" : {
"user_agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..." ,
"ip_address" : "192.168.1.5"
}
}
]
}
Use case: Session management UI
Display a list of active sessions to users so they can manage their devices:
This allows users to:
View all devices where they’re logged in
See when each session was created
Revoke sessions from unfamiliar devices
Deleting sessions
Sign out of a session
Delete a specific session using the DeleteSession endpoint:
curl -X DELETE 'https://api.moonkey.fun/v1/auth/sessions/delete' \
-H 'Authorization: Bearer sk_test_your_api_key' \
-H 'Content-Type: application/json' \
-d '{
"session_token": "vy9YGpubKjVn98cw1nT25Msj7jaIpHBinUfD45KLdAOgn9NqEuE4qGHOEchEG5Ue"
}'
Delete by session ID
You can also delete a session by its ID (useful for revoking other devices):
curl -X DELETE 'https://api.moonkey.fun/v1/auth/sessions/delete' \
-H 'Authorization: Bearer sk_test_your_api_key' \
-H 'Content-Type: application/json' \
-d '{
"session_id": "session_xyz789"
}'
Implementation patterns
Backend middleware
Implement session verification as middleware in your backend:
// middleware/auth.js
async function requireAuth ( req , res , next ) {
const sessionToken = req . headers [ 'session-token' ];
if ( ! sessionToken ) {
return res . status ( 401 ). json ({ error: 'No session token provided' });
}
try {
const response = await fetch ( 'https://api.moonkey.fun/v1/auth/sessions/verify' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . MOONKEY_SECRET_KEY } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ session_token: sessionToken })
});
if ( ! response . ok ) {
return res . status ( 401 ). json ({ error: 'Invalid session' });
}
const { session , user } = await response . json ();
// Attach user to request
req . user = user ;
req . session = session ;
next ();
} catch ( error ) {
return res . status ( 500 ). json ({ error: 'Session verification failed' });
}
}
// Use in routes
app . get ( '/api/profile' , requireAuth , ( req , res ) => {
res . json ({ user: req . user });
});
Client-side session handling
When using manual REST API implementation (not the SDK):
// Store session after login
async function login ( email , code ) {
const response = await fetch ( '/api/auth/verify-otp' , {
method: 'POST' ,
body: JSON . stringify ({ email , code })
});
const { session_token , session_jwt , user } = await response . json ();
// Store in IndexedDB or secure storage
await storeSession ({ session_token , session_jwt , user });
}
// Include session in requests
async function makeAuthenticatedRequest ( url , options = {}) {
const session = await getSession ();
return fetch ( url , {
... options ,
headers: {
... options . headers ,
'session-token' : session . session_token
}
});
}
// Handle session expiration
async function handleResponse ( response ) {
if ( response . status === 401 ) {
// Session expired or invalid
await clearSession ();
redirectToLogin ();
}
return response ;
}
Security best practices
Backend verification
Always verify on the backend - Never trust client-side session validation
Use middleware - Centralize session verification logic
Check on every request - Verify sessions for all protected endpoints
Handle errors gracefully - Clear invalid sessions and redirect to login
Session storage
Use IndexedDB - More secure than localStorage for session storage
Secure cookies as alternative - Use httpOnly, secure, and sameSite flags
Never expose in logs - Don’t log session tokens or JWTs
Clear on logout - Always delete session data from client storage
Session lifecycle
Implement proper logout - Always call the delete session endpoint
Allow session revocation - Let users manage and revoke active sessions
Rotate after sensitive actions - Create new sessions after password changes
Monitor suspicious activity - Track unusual session patterns
Common use cases
”Remember me” functionality
Implement different session durations based on user preference:
async function login ( email , code , rememberMe ) {
const sessionExpiresIn = rememberMe
? 43200 // 30 days
: 1440 ; // 1 day
const response = await verifyOTP ( email , code , sessionExpiresIn );
return response ;
}
Automatic session extension
Extend sessions on user activity:
// Extend session on each verified request
async function verifyAndExtendSession ( sessionToken ) {
return await fetch ( 'https://api.moonkey.fun/v1/auth/sessions/verify' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ apiKey } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
session_token: sessionToken ,
session_expires_in: 10080 // Reset to 7 days
})
});
}
Troubleshooting
Session not found
Cause: Session was deleted, expired, or never existed
Solution:
Check if the session token is correct
Verify the session hasn’t expired
Ensure the session wasn’t manually deleted
Clear client-side storage and redirect to login
Unauthorized errors
Cause: API key is missing or incorrect
Solution:
Verify your API key is correct
Ensure you’re using Bearer token format
Check that the API key hasn’t been revoked
Confirm you’re using the secret key (not public key)
Session expired too quickly
Cause: Session duration is too short
Solution:
Increase session_expires_in when creating sessions
Implement automatic session extension on user activity
Configure longer default duration in dashboard