Skip to content

Authentication

GLACIS uses API key authentication for management operations and bearer tokens for attestation operations.

API Keys

API keys are used for all dashboard and management API operations.

Creating API Keys

  1. Log into the GLACIS Dashboard
  2. Navigate to Settings → API Keys
  3. Click Create API Key
  4. Copy the key (you won’t be able to see it again)

API keys have the format: glc_live_... or glc_test_...

Using API Keys

Include the API key in the Authorization header:

Terminal window
curl https://api.glacis.io/api/v1/orgs/org_xyz/controls \
-H "Authorization: Bearer glc_live_abc123..."

API Key Scopes

ScopeDescriptionEndpoints
read:controlsRead control libraryGET /controls
write:evidenceManage evidencePOST/PUT /evidence
read:complianceView compliance scoresGET /compliance
write:attestationsSubmit attestationsPOST /attestations
adminFull accessAll endpoints

Bearer Tokens

Bearer tokens are epoch-bound tokens used by sidecars for attestation submission.

Obtaining Bearer Tokens

Sidecars obtain bearer tokens from the witness service:

const response = await fetch('https://witness.glacis.io/api/v1/s3p/heartbeat', {
method: 'POST',
headers: {
'Authorization': 'Bearer glc_live_abc123...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
sidecarId: 'sidecar_abc123',
organizationId: 'org_xyz789'
})
});
const { bearerToken, epochId, expiresAt } = await response.json();

Using Bearer Tokens

Bearer tokens are used for attestation submission:

const response = await fetch('https://receipts.glacis.io/api/v1/attestations', {
method: 'POST',
headers: {
'Authorization': 'Bearer wt_abc123...', // Bearer token, NOT API key
'Content-Type': 'application/json'
},
body: JSON.stringify({
epochId: 'epoch_2024010112',
level: 'L0',
// ... attestation data
})
});

Token Expiration

Bearer tokens expire with their epoch (default: 1 hour). Handle expiration gracefully:

class TokenManager {
private token: string | null = null;
private expiresAt: number = 0;
async getToken(): Promise<string> {
// Refresh 5 minutes before expiration
if (!this.token || Date.now() > this.expiresAt - 300000) {
const { bearerToken, expiresAt } = await this.refreshToken();
this.token = bearerToken;
this.expiresAt = expiresAt;
}
return this.token;
}
private async refreshToken() {
const response = await fetch('https://witness.glacis.io/api/v1/s3p/heartbeat', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.GLACIS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
sidecarId: process.env.SIDECAR_ID,
organizationId: process.env.GLACIS_ORG_ID
})
});
return response.json();
}
}

Session Authentication

The dashboard uses session-based authentication for browser access.

Login

const response = await fetch('https://app.glacis.io/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'secure_password'
}),
credentials: 'include' // Important for session cookie
});

Session Cookies

After login, the session cookie is automatically included in subsequent requests:

  • Cookie name: glacis_session
  • HttpOnly: Yes
  • Secure: Yes (HTTPS only)
  • SameSite: Strict

Webhook Signatures

GLACIS signs webhook payloads for verification:

import { createHmac } from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === `sha256=${expected}`;
}
// In your webhook handler
app.post('/webhooks/glacis', (req, res) => {
const signature = req.headers['x-glacis-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
});

Rate Limits

Endpoint TypeRate LimitWindow
Management API1,000 req/minPer API key
Attestation API10,000 req/minPer organization
Witness Heartbeat100 req/minPer sidecar
Dashboard API100 req/minPer session

Rate limit headers are included in responses:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1704106860

Error Responses

Authentication errors return standard HTTP status codes:

StatusErrorDescription
401UNAUTHORIZEDMissing or invalid credentials
403FORBIDDENValid credentials, insufficient scope
429RATE_LIMITEDToo many requests
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid API key",
"details": {
"hint": "Check that your API key is correct and not expired"
}
}
}

Security Best Practices

  1. Rotate keys regularly: Create new keys and deprecate old ones quarterly
  2. Use minimal scopes: Only request the permissions you need
  3. Monitor usage: Review API key activity in the dashboard
  4. Environment variables: Never hardcode keys in source code
  5. Separate environments: Use different keys for test and production