Authentication
Eden implements a secure, token-based authentication system using JSON Web Tokens (JWT). This approach provides a stateless authentication mechanism that's both secure and scalable, allowing the API to maintain security without storing session data.
Understanding JWT AuthenticationCopied!
JSON Web Tokens are an industry standard (RFC 7519) for securely transmitting information between parties. Each token contains encoded JSON objects and is cryptographically signed to ensure the information hasn't been tampered with. In Eden, these tokens contain information about the user's identity and permissions.
A typical JWT token flow in Eden works as follows:
-
The client authenticates using credentials and receives a JWT token
-
For subsequent requests, the client includes this token in the Authorization header
-
Eden validates the token signature and extracts user information without needing to query a database
-
If valid, the request proceeds; if invalid or expired, authentication fails
Getting Started with AuthenticationCopied!
-
Login to obtain a JWT token
-
Endpoint:
POST /auth/login
-
This endpoint requires basic authentication (username/password) to verify identity
-
You must include the Organization ID in the
X-Org-Id
header to specify which organization you're accessing -
Upon successful authentication, you'll receive a JWT token with an expiration time
-
Example request:
POST /auth/loginHeaders: X-Org-Id: YourOrgId Authorization: Basic base64(username:password)
-
-
Using your JWT token
-
Include the token in the Authorization header for all subsequent API calls
-
Use the Bearer authentication scheme
-
Example:
GET /endpoints/myEndpointHeaders: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-
-
Refresh your token
-
Endpoint:
GET /auth/refresh
-
JWT tokens have a limited lifespan to enhance security
-
Before expiration, call this endpoint to receive a new token
-
The current token must be valid to obtain a new one
-
This maintains continuous authentication without requiring re-login
-
-
Password Reset
-
Endpoint:
POST /auth/password/reset
-
Provides a secure way to reset passwords when forgotten
-
Initiates a reset process that typically involves email verification
-
This is separate from changing a known password
-
Follows security best practices for account recovery
-
Security ConsiderationsCopied!
-
JWT tokens should be treated as sensitive credentials and transmitted only over HTTPS
-
Store tokens securely on client systems, preferably in memory for web applications
-
Implement token refresh logic to handle expiration gracefully
-
Never send tokens in URL parameters to avoid accidental leakage in logs
-
The short lifespan of tokens limits the damage if a token is compromised
API ReferenceCopied!
Login
-
URL:
/auth/login
-
Method:
POST
-
Headers Required:
-
X-Org-Id
: Organization ID (e.g., "TestOrg") -
Basic Authentication credentials
-
-
Request Body: Organization details
-
Success Response: 200 OK with JWT token
-
Error Response: 401 Unauthorized
-
Example Response:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires": "2025-05-12T10:45:22Z", "user": { "username": "jane.doe@example.com", "accessLevel": "Admin" }}
Refresh Token
-
URL:
/auth/refresh
-
Method:
GET
-
Headers Required: Authorization with JWT token
-
Success Response: 200 OK with refreshed JWT token
-
Error Response: 401 Unauthorized if token is invalid or expired
-
Example Response:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires": "2025-05-12T12:45:22Z", "user": { "username": "jane.doe@example.com", "accessLevel": "Admin" }}
Request Password Reset
-
URL:
/auth/password/reset
-
Method:
POST
-
Request Body: Password reset request details
-
Example Request:
{ "email": "jane.doe@example.com", "redirectUrl": "https://your-app.example.com/reset-confirmation"}
-
Success Response: 200 OK with confirmation message
-
Example Response:
{ "message": "Password reset instructions have been sent to your email address", "requestId": "pr_123456"}
Common Authentication IssuesCopied!
Token Expiration
If your token expires, you'll receive a 401 Unauthorized response. Implement proactive token refresh by:
-
Tracking token expiration time
-
Refreshing tokens before they expire
-
Having a fallback to the login flow if refresh fails
Invalid Credentials
If login credentials are incorrect, the server returns a 401 Unauthorized response. To handle this:
-
Provide clear error messages to users
-
Implement account lockout policies for repeated failures
-
Log authentication failures for security monitoring
Missing Organization ID
If the X-Org-Id
header is missing in the login request, authentication will fail. Ensure that:
-
Your application correctly stores organization IDs
-
The header is included in all authentication requests
-
Users are provided a way to select their organization if they belong to multiple
Integration ExamplesCopied!
Web Application Authentication Flow
// Login function
async function login(username, password, orgId) {
const credentials = btoa(`${username}:${password}`);
const response = await fetch('/auth/login', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'X-Org-Id': orgId
}
});
if (response.ok) {
const data = await response.json();
// Store token securely
sessionStorage.setItem('token', data.token);
sessionStorage.setItem('tokenExpires', data.expires);
return data;
} else {
throw new Error('Authentication failed');
}
}
// Token refresh function
async function refreshToken() {
const currentToken = sessionStorage.getItem('token');
const response = await fetch('/auth/refresh', {
method: 'GET',
headers: {
'Authorization': `Bearer ${currentToken}`
}
});
if (response.ok) {
const data = await response.json();
// Update stored token
sessionStorage.setItem('token', data.token);
sessionStorage.setItem('tokenExpires', data.expires);
return data;
} else {
// Redirect to login page if refresh fails
window.location.href = '/login';
}
}
// Automatic token refresh setup
function setupTokenRefresh() {
const tokenExpires = new Date(sessionStorage.getItem('tokenExpires'));
const refreshTime = new Date(tokenExpires.getTime() - (5 * 60 * 1000)); // 5 minutes before expiry
const now = new Date();
const timeUntilRefresh = refreshTime - now;
if (timeUntilRefresh > 0) {
setTimeout(refreshToken, timeUntilRefresh);
} else {
refreshToken();
}
}
API Client Integration
import requests
import base64
import time
from datetime import datetime, timedelta
class EdenClient:
def __init__(self, base_url, org_id):
self.base_url = base_url
self.org_id = org_id
self.token = None
self.token_expiry = None
def login(self, username, password):
credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
headers = {
'Authorization': f'Basic {credentials}',
'X-Org-Id': self.org_id
}
response = requests.post(f"{self.base_url}/auth/login", headers=headers)
if response.status_code == 200:
data = response.json()
self.token = data['token']
self.token_expiry = datetime.fromisoformat(data['expires'].replace('Z', '+00:00'))
return True
return False
def refresh_token_if_needed(self):
# Refresh if token will expire in the next 5 minutes
if self.token_expiry and self.token_expiry - timedelta(minutes=5) <= datetime.now(self.token_expiry.tzinfo):
self.refresh_token()
def refresh_token(self):
headers = {'Authorization': f'Bearer {self.token}'}
response = requests.get(f"{self.base_url}/auth/refresh", headers=headers)
if response.status_code == 200:
data = response.json()
self.token = data['token']
self.token_expiry = datetime.fromisoformat(data['expires'].replace('Z', '+00:00'))
return True
return False
def request(self, method, endpoint, data=None):
self.refresh_token_if_needed()
headers = {'Authorization': f'Bearer {self.token}'}
url = f"{self.base_url}/{endpoint}"
if method.upper() == 'GET':
response = requests.get(url, headers=headers)
elif method.upper() == 'POST':
response = requests.post(url, headers=headers, json=data)
elif method.upper() == 'PATCH':
response = requests.patch(url, headers=headers, json=data)
elif method.upper() == 'DELETE':
response = requests.delete(url, headers=headers)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
return response