Overview
The Authentication API provides endpoints for user authentication, token management, and session handling. Supports both JWT token-based and Redis session-based authentication modes.
v2.1.0 adds Keycloak SSO support and Redis session management for production deployments.
Base URL
https://api.yourdomain.com
Authentication Modes
Stateless JWT authentication
Client receives access token + refresh token
Access token included in Authorization header
Refresh token used to get new access tokens
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Endpoints
POST /auth/login
Authenticate user and create session or issue tokens.
OAuth2 grant type. Options: password, refresh_token
Request Example :
curl -X POST https://api.yourdomain.com/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "alice",
"password": "password123"
}'
``` python
``` python Python
import httpx
response = httpx.post (
"https://api.yourdomain.com/auth/login" ,
json = {
"username" : "alice",
"password" : "password123"
}
)
data = response.json ()
print ( f "Access Token: {data['access_token']}" )
Response (Token Mode) :
{
"access_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." ,
"refresh_token" : "def50200abc123..." ,
"token_type" : "Bearer" ,
"expires_in" : 3600 ,
"user" : {
"id" : "alice" ,
"username" : "alice" ,
"email" : "alice@example.com" ,
"roles" : [ "user" , "admin" ]
}
}
Response (Session Mode) :
{
"session_id" : "abc123def456..." ,
"user" : {
"id" : "alice" ,
"username" : "alice" ,
"email" : "alice@example.com" ,
"roles" : [ "user" , "admin" ]
},
"expires_at" : "2025-10-13T10:30:00Z"
}
Status Codes :
Authentication successful
Invalid credentials {
"error" : "unauthorized" ,
"message" : "Invalid username or password"
}
Rate limit exceeded {
"error" : "rate_limit_exceeded" ,
"message" : "Too many login attempts. Try again in 60 seconds." ,
"retry_after" : 60
}
POST /auth/refresh
Refresh access token using refresh token.
Valid refresh token from login response
Request Example :
curl -X POST https://api.yourdomain.com/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "def50200abc123..."
}'
Response :
{
"access_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." ,
"refresh_token" : "def50200xyz789..." ,
"token_type" : "Bearer" ,
"expires_in" : 3600
}
Refresh tokens are rotated on each refresh for security. The old refresh token is invalidated.
Status Codes :
Token refreshed successfully
Invalid or expired refresh token {
"error" : "unauthorized" ,
"message" : "Invalid or expired refresh token"
}
POST /auth/logout
Logout user and revoke session/tokens.
Headers :
Authorization: Bearer {token} (token mode)
Cookie: session_id={session_id} (session mode)
Request Example :
curl -X POST https://api.yourdomain.com/auth/logout \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
Response :
{
"message" : "Logged out successfully"
}
Status Codes :
GET /auth/me
Get current authenticated user information.
Headers :
Authorization: Bearer {token} (token mode)
Cookie: session_id={session_id} (session mode)
Request Example :
curl https://api.yourdomain.com/auth/me \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
Response :
{
"id" : "alice" ,
"username" : "alice" ,
"email" : "alice@example.com" ,
"email_verified" : true ,
"roles" : [ "user" , "admin" ],
"groups" : [ "/admins" , "/users/engineering" ],
"created_at" : "2025-01-01T00:00:00Z" ,
"last_login" : "2025-10-12T10:00:00Z"
}
Status Codes :
User information retrieved
Not authenticated or session/token expired
GET /auth/sessions
List active sessions for current user (session mode only).
Headers :
Authorization: Bearer {token} or
Cookie: session_id={session_id}
Request Example :
curl https://api.yourdomain.com/auth/sessions \
-H "Cookie: session_id=abc123def456..."
Response :
{
"sessions" : [
{
"session_id" : "abc123def456..." ,
"created_at" : "2025-10-12T10:00:00Z" ,
"expires_at" : "2025-10-13T10:00:00Z" ,
"last_accessed" : "2025-10-12T14:30:00Z" ,
"ip_address" : "192.168.1.100" ,
"user_agent" : "Mozilla/5.0..." ,
"is_current" : true
},
{
"session_id" : "xyz789..." ,
"created_at" : "2025-10-11T08:00:00Z" ,
"expires_at" : "2025-10-12T08:00:00Z" ,
"last_accessed" : "2025-10-11T16:45:00Z" ,
"ip_address" : "192.168.1.50" ,
"user_agent" : "Mobile Safari..." ,
"is_current" : false
}
],
"total" : 2 ,
"max_concurrent" : 5
}
Status Codes :
DELETE /auth/sessions/
Revoke a specific session (session mode only).
Path Parameters :
session_id: Session ID to revoke
Request Example :
curl -X DELETE https://api.yourdomain.com/auth/sessions/xyz789... \
-H "Cookie: session_id=abc123def456..."
Response :
{
"message" : "Session revoked successfully"
}
Status Codes :
Cannot revoke another user’s session
POST /auth/verify
Verify token validity and get user information.
Headers :
Authorization: Bearer {token}
Request Example :
curl -X POST https://api.yourdomain.com/auth/verify \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
Response :
{
"valid" : true ,
"user_id" : "alice" ,
"username" : "alice" ,
"expires_at" : "2025-10-12T11:00:00Z" ,
"issued_at" : "2025-10-12T10:00:00Z"
}
Status Codes :
Token is invalid or expired {
"valid" : false ,
"error" : "Token expired" ,
"expired_at" : "2025-10-12T09:00:00Z"
}
Keycloak SSO Endpoints
When AUTH_PROVIDER=keycloak, additional endpoints are available:
GET /auth/keycloak/login
Redirect to Keycloak login page (browser flow).
Query Parameters :
redirect_uri: URL to redirect after login (optional)
Request Example :
curl https://api.yourdomain.com/auth/keycloak/login?redirect_uri=https://app.yourdomain.com/dashboard
Response :
302 Found
Location : https://sso.yourdomain.com/realms/mcp-server-langgraph/protocol/openid-connect/auth?client_id=...
GET /auth/keycloak/callback
OAuth2 callback endpoint (handled automatically).
Query Parameters :
code: Authorization code from Keycloak
state: CSRF protection state
This endpoint exchanges the authorization code for tokens and creates a session.
GET /auth/keycloak/logout
Logout from Keycloak and revoke tokens.
Request Example :
curl https://api.yourdomain.com/auth/keycloak/logout \
-H "Cookie: session_id=abc123def456..."
Response :
302 Found
Location : https://sso.yourdomain.com/realms/mcp-server-langgraph/protocol/openid-connect/logout
Error Responses
All authentication endpoints may return the following errors:
401 Unauthorized
{
"error" : "unauthorized" ,
"message" : "Invalid credentials or expired token" ,
"code" : "AUTH_INVALID_CREDENTIALS"
}
403 Forbidden
{
"error" : "forbidden" ,
"message" : "Access denied" ,
"code" : "AUTH_ACCESS_DENIED"
}
429 Too Many Requests
{
"error" : "rate_limit_exceeded" ,
"message" : "Too many requests. Please try again later." ,
"retry_after" : 60 ,
"code" : "AUTH_RATE_LIMIT"
}
500 Internal Server Error
{
"error" : "internal_error" ,
"message" : "Authentication service unavailable" ,
"trace_id" : "abc123..." ,
"code" : "AUTH_SERVICE_ERROR"
}
SDK Examples
Python
from mcp_server_langgraph.auth.middleware import AuthMiddleware
## Initialize auth
auth = AuthMiddleware()
## Login (development mode)
token = auth.create_token( "alice" , expires_in = 3600 )
## Make authenticated request
import httpx
response = httpx.post(
"https://api.yourdomain.com/message" ,
headers = { "Authorization" : f "Bearer { token } " },
json = { "query" : "Hello!" }
)
JavaScript/TypeScript
class AuthClient {
constructor ( baseUrl ) {
this . baseUrl = baseUrl ;
this . token = null ;
}
async login ( username , password ) {
const response = await fetch ( ` ${ this . baseUrl } /auth/login` , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ username , password })
});
const data = await response . json ();
this . token = data . access_token ;
return data ;
}
async request ( endpoint , options = {}) {
return fetch ( ` ${ this . baseUrl }${ endpoint } ` , {
... options ,
headers: {
... options . headers ,
'Authorization' : `Bearer ${ this . token } `
}
});
}
}
// Usage
const client = new AuthClient ( 'https://api.yourdomain.com' );
await client . login ( 'alice' , 'password123' );
const response = await client . request ( '/message' , {
method: 'POST' ,
body: JSON . stringify ({ query: 'Hello!' })
});
Security Best Practices
Browser : Store access tokens in memory, refresh tokens in HttpOnly cookiesMobile : Use secure storage (Keychain/Keystore)Server : Store tokens in environment variables or secret managerNever : Store tokens in localStorage (vulnerable to XSS)
Refresh tokens before expiration (e.g., when < 5 minutes left)
Implement automatic retry on 401 with token refresh
Handle refresh token rotation
Clear tokens on logout
Set appropriate session TTL (balance UX vs security)
Use sliding windows for active users
Limit concurrent sessions per user
Revoke sessions on password change
Monitor for session hijacking
Implement exponential backoff on failures
Respect Retry-After header on 429 errors
Monitor authentication failure rates
Alert on suspicious patterns
Secure by Default : All authentication endpoints use industry-standard security practices!