Atom

Credentials

Managing password, API key, and certificate credentials for entities.

Credentials are attached to entities. An entity may have multiple credentials of different kinds.

Supported credential kinds:

  • password;
  • API key;
  • certificate.

This page covers passwords and API keys. See Certificates for mTLS certificate credentials, CA files, CRL, OCSP, and runtime lookup.

Password credentials

Used for the /auth/login endpoint. The password is hashed with argon2 before storage; the plaintext is never persisted.

# Set a password for an entity
curl -X POST http://localhost:8080/entities/$ENTITY_ID/credentials/password \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"password": "s3cur3-p@ssw0rd"}'

Login returns a JWT and session reference:

curl -X POST http://localhost:8080/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"identifier": "alice@example.com", "secret": "s3cur3-p@ssw0rd"}'
{
  "token":      "eyJ...",
  "entity_id":  "...",
  "session_id": "...",
  "expires_at": "2025-01-01T01:00:00Z"
}

If ATOM_SELF_REGISTRATION_ENABLED=true, a human can self-register into an existing global account without selecting a tenant. Password signup stores the normalized email as the login identifier and requires email verification before normal login:

curl -X POST http://localhost:8080/auth/signup \
  -H 'Content-Type: application/json' \
  -d '{"name": "Alice", "email": "alice@example.com", "password": "s3cur3-p@ssw0rd"}'

Verification and resend endpoints are public:

curl 'http://localhost:8080/auth/email/verify?token=atomv_...'
 
curl -X POST http://localhost:8080/auth/email/resend \
  -H 'Content-Type: application/json' \
  -d '{"email": "alice@example.com"}'

ATOM_ALLOW_UNVERIFIED_EMAIL_LOGIN=true allows local development login before email verification, but inactive and suspended entities are still rejected.

API keys

API keys are long-lived credentials suited for device and service authentication where interactive login is not practical.

Format

atom_<32-hex-credential-id>_<64-hex-secret>

The credential ID is embedded in the key for O(1) lookup — the server decodes the ID from the prefix and fetches that specific credential row, then verifies the argon2-hashed secret.

Creating an API key

curl -X POST http://localhost:8080/entities/$ENTITY_ID/credentials/api-keys \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"description": "device-01 production key"}'
{
  "credential_id": "...",
  "key":           "atom_<id>_<secret>",
  "expires_at":    null
}

The full key is returned exactly once at creation time. It is never stored in plaintext and cannot be recovered. Store it securely immediately.

You can set an expiry:

-d '{"expires_at": "2026-01-01T00:00:00Z", "description": "temporary key"}'

Using an API key

Pass it as a Bearer token — the service detects the atom_ prefix and routes to API key verification:

curl http://localhost:8080/entities/$ENTITY_ID \
  -H "Authorization: Bearer atom_<id>_<secret>"

API key authentication does not create a session and does not return a JWT.

Listing credentials

curl http://localhost:8080/entities/$ENTITY_ID/credentials \
  -H "Authorization: Bearer $TOKEN"

Returns metadata only — no secret hashes, no plaintext secrets.

{
  "items": [
    {
      "id":         "...",
      "kind":       "api_key",
      "identifier": "atom_abc12...",
      "status":     "active",
      "expires_at": null,
      "created_at": "2025-01-01T00:00:00Z"
    }
  ]
}

Revoking a credential

curl -X DELETE \
  http://localhost:8080/entities/$ENTITY_ID/credentials/$CRED_ID \
  -H "Authorization: Bearer $TOKEN"

The credential status is set to revoked. Revoked credentials are rejected immediately on the next request — no token reissuance is required because API keys are verified live against the database on each request.

On this page