Skip to main content
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 -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 CaseDuration (minutes)Duration (days)
Short session1,4401 day
Standard session10,0807 days
Remember me43,20030 days
Maximum duration527,040366 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: List of active sessions UI 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