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 Settings → API 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/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/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/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 · Service status