Certs
Issue, renew and revoke device/gateway certificates for mTLS through Atom's certificate API.
Certificate issuance is provided by Atom, for mutual TLS between devices/gateways and the platform. There is no standalone certs HTTP service or CLI command — everything below is Atom's GraphQL API, same connection details as the rest of this reference: POST http://localhost:8080/graphql, Content-Type: application/json, Authorization: Bearer <user_token>.
Configuration
Certificate issuance is enabled per deployment:
ATOM_CERTS_ENABLED=true
ATOM_CERTS_CA_MODE=file_root_issuer
ATOM_CERTS_ROOT_CA_CERT_PATH=/certs/ca.crt
ATOM_CERTS_ROOT_CA_KEY_PATH=/certs/ca.keyATOM_CERTS_CA_DIR (defaulting to ./ssl/certs) is mounted into the Atom container as /certs, so the root CA cert/key paths above are read from there. ATOM_CERTS_LEAF_DEFAULT_TTL_SECS and ATOM_CERTS_LEAF_MAX_TTL_SECS bound how long an issued leaf certificate is valid for.
Issue a certificate
Two ways to issue: Atom generates the key pair for you, or you supply your own CSR.
Generated key pair
curl -sSiX POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d @- <<EOF
{
"query": "mutation IssueCert(\$input: IssueGeneratedCertificateV2Input!) { issueGeneratedCertificateV2(input: \$input) { certificate { credentialId serialNumber expiresAt } privateKeyPem chainPem } }",
"variables": {
"input": {
"entityId": "<device_id>",
"ttlSecs": 31536000
}
}
}
EOFThe response's privateKeyPem is only returned once, at issuance — Atom does not store it.
From a CSR
curl -sSiX POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d @- <<EOF
{
"query": "mutation IssueFromCSR(\$input: IssueCertificateFromCsrV2Input!) { issueCertificateFromCsrV2(input: \$input) { certificate { credentialId serialNumber expiresAt } } }",
"variables": {
"input": {
"entityId": "<device_id>",
"csrPem": "<csr_pem_content>",
"ttlSecs": 31536000,
"idempotencyKey": "<client_generated_uuid>"
}
}
}
EOFidempotencyKey is required on the CSR path — a retried request with the same key replays the original result (idempotentReplay: true) instead of issuing a second certificate.
View / list certificates
curl -sSiX POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d @- <<EOF
{
"query": "query Certs(\$entityId: ID, \$status: String, \$limit: Int, \$offset: Int) { certificates(entityId: \$entityId, status: \$status, limit: \$limit, offset: \$offset) { total items { credentialId serialNumber status expiresAt } } }",
"variables": { "entityId": "<device_id>", "status": "active", "limit": 20, "offset": 0 }
}
EOFA single certificate can be fetched with certificate(credentialId: ID!).
Renew a certificate
curl -sSiX POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d @- <<EOF
{
"query": "mutation RenewCert(\$input: RenewGeneratedCertificateV2Input!) { renewGeneratedCertificateV2(input: \$input) { certificate { credentialId serialNumber expiresAt } privateKeyPem } }",
"variables": {
"input": {
"credentialId": "<credential_id>",
"ttlSecs": 31536000,
"revokeOld": true,
"idempotencyKey": "<client_generated_uuid>"
}
}
}
EOFrenewCertificateFromCsrV2 is the CSR-based equivalent, taking credentialId/csrPem instead of generating a new key pair. revokeOld: true revokes the certificate being renewed once the new one is issued.
Revoke a certificate
curl -sSiX POST http://localhost:8080/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d @- <<EOF
{
"query": "mutation RevokeCert(\$input: RevokeCertificateV2Input!) { revokeCertificateV2(input: \$input) { certificate { credentialId status } } }",
"variables": { "input": { "credentialId": "<credential_id>", "reason": "device decommissioned" } }
}
EOFRevokeCertificateV2Input also accepts serialNumber or fingerprintSha256 in place of credentialId. To revoke everything an entity holds, use revokeEntityCertificates(entityId: ID!, reason: String): Int! — it returns the number revoked. For a workspace- or issuer-wide sweep, bulkRevokeCertificates pages through matching certificates via afterCredentialId/snapshotAt cursors.
CA, CRL and OCSP
These are plain HTTPS routes served directly by Atom, not GraphQL:
curl https://<atom-host>/certs/trust-bundle.pem
curl https://<atom-host>/certs/issuers/<issuer_id>/crl
curl https://<atom-host>/certs/issuers/<issuer_id>/ocspATOM_PUBLIC_URL (or ATOM_PUBLIC_BASE_URL) must be set for these routes to be reachable at a stable, publicly-resolvable address — devices validating a peer's chain or checking revocation status need a URL they can actually reach, not localhost.
Storage
Configure Magistrala storage with writers and readers for Cassandra, MongoDB, InfluxDB, PostgreSQL and TimescaleDB via Docker add-ons.
Agent
Magistrala IoT Agent runs on edge devices, connects them to Magistrala over MQTT, exposes a local HTTP API, manages Node-RED flows, executes commands, tracks local services, and serves as the bridge between local workloads and the cloud.