Authenticate users
A standalone server answers three questions on every request:
- Who is calling? A JWT or a ticket says.
- May they act in this organization? A membership list or a directory service says.
- What is their role in this scope? The same list or service says.
This guide sets up all three. In the ModularIoT web app, ModularIoT answers them for you; skip this guide.
1. Verify who is calling
JWT
Most identity providers issue JWTs: Auth0, Microsoft Entra ID, Keycloak, Okta, Google. Install jose next to the server (the container image already has it), then set the issuer, the audience and one key source:
MIOT_DASHBOARD_JWT_ISSUER=https://your-company.auth0.com/
MIOT_DASHBOARD_JWT_AUDIENCE=miot-dashboards
MIOT_DASHBOARD_JWT_JWKS_URL=https://your-company.auth0.com/.well-known/jwks.json
MIOT_DASHBOARD_JWT_USER_CLAIM=email| Key source | Algorithm | Use when |
|---|---|---|
MIOT_DASHBOARD_JWT_JWKS_URL | RS256 | The provider publishes its keys. The usual choice. |
MIOT_DASHBOARD_JWT_PUBLIC_KEY | RS256 | You have the public key as PEM |
MIOT_DASHBOARD_JWT_SECRET | HS256 | You share a secret of at least 32 bytes with the issuer |
Set exactly one. The server accepts only that algorithm.
MIOT_DASHBOARD_JWT_USER_CLAIM names the claim that identifies the person. It defaults to sub. Whatever it holds is the ID you use in memberships and in dashboard permissions, so pick one that is readable and stable, such as email.
Callers send the token as Authorization: Bearer <token>.
2 and 3. Say who belongs where
Membership file
For a few dozen people, list them in a JSON file and point MIOT_DASHBOARD_SEED at it. The shape is organization, then scope, then person, then role:
{
"memberships": {
"acme": {
"operations": {
"ana@acme.example": "Coordinator",
"luis@acme.example": "Editor",
"sofia@acme.example": "Consumer"
},
"finance": {
"ana@acme.example": "Consumer"
}
}
}
}A person may act in an organization when they appear in any of its scopes. The server reads the file at startup, so a change needs a restart.
Check it
Restart the server and read its startup log:
{"msg":"identity","auth":"RS256 bearer tokens from https://your-company.auth0.com/ ..."}
{"msg":"tenants","entitlement":"the seed file (1 tenants)"}
{"msg":"scopes","membership":"the seed file (1 tenants)"}If tenants or scopes says 0 tenants, the server knows nobody and answers 403 to everything.
Then call it with a real token:
curl -H "Authorization: Bearer $TOKEN" \
https://dashboards.example.com/tenants/acme/scopes/operations/dashboardsNever combine MIOT_DASHBOARD_INSECURE_AUTH with a real deployment. The server refuses to start with it when NODE_ENV=production, when it listens beyond localhost, or when JWT or ticket settings are also present.
Groups
To use allowedGroups on dashboards, the server must know each person’s groups. Set MIOT_DASHBOARD_JWT_GROUPS_CLAIM to the token claim that lists them, or MIOT_DASHBOARD_TICKET_GROUPS_PATH for tickets. Use IDs that are unique across organizations. See Share and set permissions.