Skip to content

Authentication

Essence Platform provides multiple authentication methods to secure your API requests. Choose the method that best fits your use case.

Authentication Methods

MethodBest ForSecurity LevelUse Case
API KeysServer-to-serverHighBackend services, automation
JWT Bearer TokensUser sessionsVery HighWeb/mobile apps, user actions
OAuth 2.0Third-party appsVery HighPartner 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

  1. Sign in to app.essence.digital
  2. Navigate to SettingsAPI Keys
  3. Click Generate New API Key
  4. Configure your API key:
    • Name: Descriptive name (e.g., "Production Backend")
    • Scopes: Select required permissions
    • Expiration: Optional expiry date
  5. 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/json

cURL 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_1a2b3c4d5e6f7g8h9i0jklmnopqrstuv1234567

API Key Scopes

API keys support fine-grained permissions:

ScopeDescriptionActions Allowed
vaults:readRead vault informationGET /vaults, GET /vaults/:id
vaults:writeCreate and update vaultsPOST /vaults, PUT /vaults/:id, DELETE /vaults/:id
documents:readRead documentsGET /documents, GET /documents/:id
documents:writeUpload and manage documentsPOST /documents, PUT /documents/:id, DELETE /documents/:id
documents:shareShare documentsPOST /documents/:id/share, GET /shares/:token
instances:readRead instance informationGET /instances, GET /instances/:id
instances:writeManage instances (admin)POST /instances, PUT /instances/:id
users:readRead user informationGET /users/me
users:writeUpdate user profilePUT /users/me
webhooks:readRead webhook configurationsGET /webhooks
webhooks:writeManage webhooksPOST /webhooks, PUT /webhooks/:id, DELETE /webhooks/:id
consents:readRead consent recordsGET /consents
consents:writeManage consentsPOST /consents, PUT /consents/:id
admin:*Full administrative accessAll 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 data

Obtaining 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 TypeLifetimePurpose
Access Token1 hourAPI authentication
Refresh Token30 daysObtain new access tokens
ID Token1 hourUser 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_token

OAuth 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/userinfo

Supported 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.digital
typescript
// 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 days

4. 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

CodeHTTP StatusDescriptionResolution
INVALID_API_KEY401API key is invalidCheck key format and validity
EXPIRED_TOKEN401JWT token expiredRefresh access token
INVALID_TOKEN401JWT token is malformedRe-authenticate user
MISSING_AUTH401No credentials providedAdd authentication header
INSUFFICIENT_PERMISSIONS403Lacks required scopeRegenerate key with correct scopes
ACCOUNT_SUSPENDED403Account suspendedContact support
IP_BLOCKED403IP address blockedContact 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 -d

3. 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


Need help? Join our Discord community or email support.

Built with ❤️ for developers