Authentication
Essence Platform provides multiple authentication methods to secure your API requests. Choose the method that best fits your use case.
Authentication Methods
| Method | Best For | Security Level | Use Case |
|---|---|---|---|
| API Keys | Server-to-server | High | Backend services, automation |
| JWT Bearer Tokens | User sessions | Very High | Web/mobile apps, user actions |
| OAuth 2.0 | Third-party apps | Very High | Partner integrations (coming soon) |
API Key Authentication
API keys are the simplest way to authenticate with the Essence Platform API. Best for server-side applications and automated processes.
Generating an API Key
- Sign in to app.essence.digital
- Navigate to Settings → API Keys
- Click Generate New API Key
- Configure your API key:
- Name: Descriptive name (e.g., "Production Backend")
- Scopes: Select required permissions
- Expiration: Optional expiry date
- Copy and securely store your API key
Security First
- API keys are shown only once during creation
- Store keys in environment variables or secrets managers
- Never commit keys to version control
- Rotate keys every 90 days
- Use separate keys for each environment
Using API Keys
HTTP Header
http
GET /api/v1/vaults HTTP/1.1
Host: api.essence.digital
X-Api-Key: essence_sk_1234567890abcdefghijklmnopqrstuvwxyz
Content-Type: application/jsoncURL Example
bash
curl -X GET "https://api.essence.digital/api/v1/vaults" \
-H "X-Api-Key: essence_sk_your_key_here" \
-H "Content-Type: application/json"SDK Example
typescript
import { EssenceClient } from '@essence-platform/sdk';
const client = new EssenceClient({
apiKey: process.env.ESSENCE_API_KEY,
baseUrl: 'https://api.essence.digital'
});
// All requests now use API key authentication
const vaults = await client.vaults.list();API Key Format
essence_sk_[40-character alphanumeric string]
Example:
essence_sk_1a2b3c4d5e6f7g8h9i0jklmnopqrstuv1234567API Key Scopes
API keys support fine-grained permissions:
| Scope | Description | Actions Allowed |
|---|---|---|
vaults:read | Read vault information | GET /vaults, GET /vaults/:id |
vaults:write | Create and update vaults | POST /vaults, PUT /vaults/:id, DELETE /vaults/:id |
documents:read | Read documents | GET /documents, GET /documents/:id |
documents:write | Upload and manage documents | POST /documents, PUT /documents/:id, DELETE /documents/:id |
documents:share | Share documents | POST /documents/:id/share, GET /shares/:token |
instances:read | Read instance information | GET /instances, GET /instances/:id |
instances:write | Manage instances (admin) | POST /instances, PUT /instances/:id |
users:read | Read user information | GET /users/me |
users:write | Update user profile | PUT /users/me |
webhooks:read | Read webhook configurations | GET /webhooks |
webhooks:write | Manage webhooks | POST /webhooks, PUT /webhooks/:id, DELETE /webhooks/:id |
consents:read | Read consent records | GET /consents |
consents:write | Manage consents | POST /consents, PUT /consents/:id |
admin:* | Full administrative access | All operations |
Scope Validation
typescript
// API key with insufficient scopes
try {
await client.documents.share(documentId, options);
} catch (error) {
if (error instanceof AuthorizationError) {
console.error('Error: API key lacks documents:share scope');
// Regenerate API key with correct scopes
}
}JWT Bearer Token Authentication
JWT (JSON Web Token) authentication is recommended for user-specific actions in web and mobile applications.
JWT Token Flow
mermaid
sequenceDiagram
participant User as User
participant App as Your Application
participant Auth as Essence Auth Service
participant API as Essence API
User->>App: Login with credentials
App->>Auth: POST /auth/login<br/>{email, password}
Auth->>Auth: Validate credentials
Auth-->>App: 200 OK<br/>{accessToken, refreshToken}
App->>App: Store tokens securely
App->>API: GET /api/v1/vaults<br/>Authorization: Bearer {accessToken}
API->>API: Validate JWT
API->>API: Check permissions
API-->>App: 200 OK + Vault dataObtaining JWT Tokens
Login with Email/Password
typescript
// Login to get JWT tokens
const response = await fetch('https://api.essence.digital/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'secure_password'
})
});
const { accessToken, refreshToken, expiresIn } = await response.json();
// Store tokens securely
localStorage.setItem('essence_access_token', accessToken);
localStorage.setItem('essence_refresh_token', refreshToken);Using JWT with SDK
typescript
import { EssenceClient } from '@essence-platform/sdk';
const client = new EssenceClient({
bearerToken: accessToken, // From login
baseUrl: 'https://api.essence.digital'
});
// All requests now use JWT authentication
const vaults = await client.vaults.list();JWT Token Structure
json
{
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-123"
},
"payload": {
"sub": "user-id-123",
"email": "user@example.com",
"iss": "https://api.essence.digital",
"aud": "essence-api",
"iat": 1699564800,
"exp": 1699651200,
"scopes": ["vaults:read", "vaults:write", "documents:read", "documents:write"]
},
"signature": "..."
}Token Expiration
| Token Type | Lifetime | Purpose |
|---|---|---|
| Access Token | 1 hour | API authentication |
| Refresh Token | 30 days | Obtain new access tokens |
| ID Token | 1 hour | User identity information |
Refreshing Tokens
typescript
async function refreshAccessToken(refreshToken: string) {
const response = await fetch('https://api.essence.digital/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken })
});
if (!response.ok) {
// Refresh token expired or invalid - user must login again
throw new Error('Session expired. Please login again.');
}
const { accessToken, refreshToken: newRefreshToken, expiresIn } = await response.json();
// Update stored tokens
localStorage.setItem('essence_access_token', accessToken);
localStorage.setItem('essence_refresh_token', newRefreshToken);
return accessToken;
}
// Automatic token refresh on API errors
async function makeAuthenticatedRequest(url: string) {
let accessToken = localStorage.getItem('essence_access_token');
try {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
if (response.status === 401) {
// Token expired - refresh and retry
const refreshToken = localStorage.getItem('essence_refresh_token');
accessToken = await refreshAccessToken(refreshToken);
// Retry request with new token
return await fetch(url, {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
}
return response;
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}Secure Token Storage
Web Applications
typescript
// ❌ BAD: Storing in localStorage (vulnerable to XSS)
localStorage.setItem('access_token', token);
// ✅ GOOD: Using httpOnly cookies
// Set cookie on server side after login
res.cookie('essence_token', accessToken, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 3600000 // 1 hour
});
// ✅ BETTER: Using secure storage library
import SecureLS from 'secure-ls';
const ls = new SecureLS({ encodingType: 'aes' });
ls.set('essence_token', accessToken);Mobile Applications
typescript
// iOS/Android: Use secure storage
import * as SecureStore from 'expo-secure-store';
// Store token securely
await SecureStore.setItemAsync('essence_access_token', accessToken);
// Retrieve token
const token = await SecureStore.getItemAsync('essence_access_token');OAuth 2.0 Authentication
OAuth 2.0 support is coming soon for third-party integrations.
Authorization Code Flow (Coming Soon)
mermaid
sequenceDiagram
participant User
participant ThirdParty as Third-Party App
participant Essence as Essence OAuth
participant API as Essence API
User->>ThirdParty: Initiates OAuth flow
ThirdParty->>Essence: Redirect to /oauth/authorize
User->>Essence: Login & grant permissions
Essence-->>ThirdParty: Redirect with auth code
ThirdParty->>Essence: POST /oauth/token<br/>{code, client_secret}
Essence-->>ThirdParty: {access_token, refresh_token}
ThirdParty->>API: API requests with access_tokenOAuth 2.0 Endpoints (Coming Soon)
Authorization: https://api.essence.digital/oauth/authorize
Token: https://api.essence.digital/oauth/token
Revoke: https://api.essence.digital/oauth/revoke
Userinfo: https://api.essence.digital/oauth/userinfoSupported Grant Types (Coming Soon)
- Authorization Code: For web and mobile apps
- Client Credentials: For server-to-server
- Refresh Token: To obtain new access tokens
- PKCE: For public clients (mobile, SPA)
Security Best Practices
1. Never Expose Credentials in Client-Side Code
typescript
// ❌ BAD: API key in client-side code
const client = new EssenceClient({
apiKey: 'essence_sk_1234567890' // Exposed to users!
});
// ✅ GOOD: Use JWT tokens in client-side code
const client = new EssenceClient({
bearerToken: userAccessToken // User-specific token
});2. Use Environment Variables
bash
# .env file (never commit this!)
ESSENCE_API_KEY=essence_sk_your_key_here
ESSENCE_API_URL=https://api.essence.digitaltypescript
// Load from environment
const client = new EssenceClient({
apiKey: process.env.ESSENCE_API_KEY,
baseUrl: process.env.ESSENCE_API_URL
});3. Rotate API Keys Regularly
typescript
// Automated key rotation (example)
async function rotateApiKey() {
// 1. Generate new API key
const newKey = await createNewApiKey({
name: 'Production Backend (Rotated)',
scopes: existingKeyScopes
});
// 2. Update environment/secrets manager
await updateSecret('ESSENCE_API_KEY', newKey.key);
// 3. Wait for deployment to use new key
await waitForDeployment();
// 4. Revoke old API key
await revokeApiKey(oldKeyId);
}
// Schedule rotation every 90 days4. Use Separate Keys per Environment
typescript
// Development
const devClient = new EssenceClient({
apiKey: process.env.ESSENCE_DEV_API_KEY,
baseUrl: 'https://dev-api.essence.digital'
});
// Staging
const stagingClient = new EssenceClient({
apiKey: process.env.ESSENCE_STAGING_API_KEY,
baseUrl: 'https://staging-api.essence.digital'
});
// Production
const prodClient = new EssenceClient({
apiKey: process.env.ESSENCE_PROD_API_KEY,
baseUrl: 'https://api.essence.digital'
});5. Implement Token Refresh Logic
typescript
class EssenceAuth {
private accessToken: string;
private refreshToken: string;
private tokenExpiry: number;
async getAccessToken(): Promise<string> {
// Check if token is expired
if (Date.now() >= this.tokenExpiry - 60000) { // Refresh 1 min before expiry
await this.refreshAccessToken();
}
return this.accessToken;
}
private async refreshAccessToken() {
const response = await fetch('https://api.essence.digital/auth/refresh', {
method: 'POST',
body: JSON.stringify({ refreshToken: this.refreshToken })
});
const { accessToken, refreshToken, expiresIn } = await response.json();
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.tokenExpiry = Date.now() + expiresIn * 1000;
}
}6. Monitor for Compromised Credentials
typescript
// Log authentication failures
app.use((req, res, next) => {
const originalSend = res.send;
res.send = function(data) {
if (res.statusCode === 401 || res.statusCode === 403) {
logger.warn('Authentication failure', {
ip: req.ip,
path: req.path,
userAgent: req.get('user-agent')
});
// Alert if multiple failures
checkForBruteForce(req.ip);
}
originalSend.call(this, data);
};
next();
});Error Handling
Authentication Errors
typescript
import { AuthenticationError, AuthorizationError } from '@essence-platform/sdk';
try {
const vaults = await client.vaults.list();
} catch (error) {
if (error instanceof AuthenticationError) {
// Invalid or missing credentials
console.error('Authentication failed:', error.message);
if (error.code === 'INVALID_API_KEY') {
// API key is invalid - check configuration
} else if (error.code === 'EXPIRED_TOKEN') {
// JWT token expired - refresh token
await refreshToken();
} else if (error.code === 'MISSING_AUTH') {
// No credentials provided
}
} else if (error instanceof AuthorizationError) {
// Valid credentials but insufficient permissions
console.error('Authorization failed:', error.message);
if (error.code === 'INSUFFICIENT_PERMISSIONS') {
// API key lacks required scope
console.error('Required scopes:', error.requiredScopes);
}
}
}Common Authentication Error Codes
| Code | HTTP Status | Description | Resolution |
|---|---|---|---|
INVALID_API_KEY | 401 | API key is invalid | Check key format and validity |
EXPIRED_TOKEN | 401 | JWT token expired | Refresh access token |
INVALID_TOKEN | 401 | JWT token is malformed | Re-authenticate user |
MISSING_AUTH | 401 | No credentials provided | Add authentication header |
INSUFFICIENT_PERMISSIONS | 403 | Lacks required scope | Regenerate key with correct scopes |
ACCOUNT_SUSPENDED | 403 | Account suspended | Contact support |
IP_BLOCKED | 403 | IP address blocked | Contact support |
Testing Authentication
1. Validate API Key
bash
# Test API key validity
curl -X GET "https://api.essence.digital/api/v1/auth/validate" \
-H "X-Api-Key: essence_sk_your_key_here"
# Response
{
"valid": true,
"keyId": "key_123",
"name": "Production Backend",
"scopes": ["vaults:read", "vaults:write"],
"expiresAt": "2026-01-01T00:00:00Z"
}2. Test JWT Token
bash
# Decode JWT token (don't send to third parties!)
echo "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." | base64 -d3. Verify Scopes
typescript
// Check available scopes
const info = await client.auth.getInfo();
console.log('Available scopes:', info.scopes);
// Verify specific scope
if (info.scopes.includes('documents:share')) {
await client.documents.share(documentId, options);
} else {
console.error('Missing documents:share scope');
}Next Steps
- Quick Start - Make your first authenticated API call
- API Reference - Explore available endpoints
- Best Practices - Security and performance tips
- Error Codes - Complete error reference
Need help? Join our Discord community or email support.