API Keys
An API key is an X.509 certificate you register with Last Lock. You keep the private key and sign short-lived JWTs with it; Link verifies each JWT against the registered certificate. Last Lock never holds a secret that can call the API on your behalf.
Registering a certificate
An organization or site admin registers certificates in the dashboard under Link Manager → API Keys. Upload a PEM or DER encoded certificate whose public key is one of:
| Key | JWT alg |
|---|---|
| ECDSA P-256 | ES256 |
| RSA, 2048 bits or more | RS256 |
| ML-DSA-44, ML-DSA-65 or ML-DSA-87 (post-quantum, FIPS 204) | ML-DSA-44, ML-DSA-65 or ML-DSA-87 |
A self-signed certificate is fine; Link uses only its public key and validity window. With OpenSSL 3.5 or later:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
-keyout key.pem -out cert.pem -days 365 -nodes -subj /CN=my-integration
# or, post-quantum:
openssl req -x509 -newkey ML-DSA-65 \
-keyout key.pem -out cert.pem -days 365 -nodes -subj /CN=my-integration
The dashboard can also generate an ECDSA or RSA key pair in your browser. The private key is downloaded to you and never sent to Last Lock.
The dashboard shows each key's key ID, the hex SHA-256 of the certificate's SubjectPublicKeyInfo. To compute it yourself:
openssl x509 -in cert.pem -pubkey -noout \
| openssl pkey -pubin -outform DER \
| openssl dgst -sha256
Revoking a key in the dashboard takes effect on the next request.
Limiting a key to sites
A key is either organization-wide or limited to one or more sites, chosen when it is registered. JWTs signed by a site-limited key:
- see and act on only the devices in those sites; any other device is reported as not found;
- receive only audits from devices in those sites;
- cannot move a device into a site outside them;
- cannot manage audit webhooks, which deliver audits from every site.
Organization admins can register keys for any sites or for the whole organization. Site admins can register, see and revoke only keys limited to sites they administer.
Signing requests
Send the JWT as a bearer token:
authorization: Bearer <jwt>
Link accepts a JWT when all of the following hold:
| Field | Requirement |
|---|---|
header alg | The algorithm for the certificate's key, from the table above |
header kid | The key ID of a registered certificate |
aud | link_<org id> |
iat, exp | Both present, exp in the future, and exp - iat at most one hour |
| certificate | Currently within its notBefore/notAfter window |
A valid JWT signed by an organization-wide key has full access to your organization's Link API; one signed by a site-limited key is confined to its sites (see above).
Example
import time, jwt # PyJWT
now = int(time.time())
token = jwt.encode(
{"aud": "link_<org id>", "iat": now, "exp": now + 300},
open("key.pem").read(),
algorithm="ES256",
headers={"kid": "<key id>"},
)
For an ML-DSA key, if your JWT library does not support ML-DSA yet, build the
token by hand: sign the standard JWS signing input,
base64url(header) + "." + base64url(payload), with ML-DSA and an empty
context string, then append "." + base64url(signature). The header is
{"alg": "ML-DSA-65", "kid": "<key id>", "typ": "JWT"} (or ML-DSA-44 /
ML-DSA-87 to match the key).