-
Notifications
You must be signed in to change notification settings - Fork 13
console auth authz proposal
- 1. Context & Problem Statement
- 2. Solution Proposals
- 3. Identity Normalization Middleware (Recommended)
- 4. Compiled in Middleware (Alternative)
Today, the Device Management Toolkit (DMT) provides runtime middleware extensibility through the Management Presence Server (MPS) and Relay Presence Server (RPS). Implemented using Node.js and Express.js, these services allow customers, ISVs, and developers to execute custom request handlers before requests reach the service, enabling capabilities such as:
- Custom authentication
- Multi-tenancy
- Request enrichment
- Trace and correlation propagation
As part of the DMT platform evolution, MPS is replaced by Console, a Go-based service, while RPS continues to be deployed unchanged.
This shift removes the previous runtime extensibility model with Console. Although Go supports middleware patterns, portable runtime loading of middleware modules is not a common deployment model.
This document describes the architectural approaches for integrating middleware support, using authentication and identity as examples, into the DMT platform to provide a consistent, secure, and maintainable model across both Console and RPS.
DMT supports two deployment models for integrating middleware. The choice depends on the operator's deployment preferences and operational constraints.
-
Identity Normalization (Recommended) : Suitable for operators who:
- Deploy DMT Console as a container (Docker or Kubernetes).
- Prefer to consume the standard DMT Console image without rebuilding it.
- Are willing to use an API gateway or identity-aware proxy to perform authentication and identity normalization.
In this model, a Trusted Identity Layer (TIL) performs authentication and provider-specific identity normalization before requests reach DMT services.
-
Compiled-in Middleware : Suitable for operators who:
- Build DMT Console from source.
- Prefer not to customize or extend their API gateway.
- Require application-specific request processing within DMT Console.
In this model, operators implement middleware components that are registered during application initialization (for example, using a RegisterCustomMiddleware extension point) and statically linked into the Console binary, unlike RPS where middleware remains runtime-extensible.
flowchart LR
C3["Client\nExternal JWT"] -->|"Bearer Token"| TIL3["Trusted Identity Layer\nAuthenticate\nValidate JWT\nNormalize Claims\nCreate Identity Envelope"]
TIL3 -->|"DMT Identity Header: Base-64-Encoded-Identity"| CON3["Console\nParse Envelope\nBuild IdentityContext\nAPI Handlers"]
TIL3 -->|"DMT Identity Header: Base-64-Encoded-Identity"| IM3["RPS Identity Middleware\nParse Envelope\nBuild IdentityContext"]
IM3 --> RPS3["RPS Business Middleware\nAPI Handlers"]
flowchart LR
Client["Client\nExternal JWT"]
GW[API Gateway\nRouting Only]
Client -->|"Bearer Token"| GW
GW -->|Original JWT| Console
GW -->|Original JWT| RPSMW
subgraph Console["Console (Go)"]
direction LR
CIM["Compiled Middleware\n• Normalize Claims\n• Build IdentityContext"]
BL["Console Business Logic"]
CIM --> BL
end
subgraph RPS["RPS"]
RH["API Handlers"]
end
subgraph Runtime["Runtime (Customer Extensions)"]
RPSMW["RPS Middleware\n• Normalize Claims\n• Build IdentityContext"]
end
RPSMW --> RH
style CIM fill:#FFE699,stroke:#B8860B,stroke-width:2px
style Console fill:#FFFFFF
style RPS fill:#FFFFFF
style Runtime fill:#F8F8F8,stroke-dasharray: 5 5
In this model, the Trusted Identity Layer (TIL) validates the JWT from an external Identity Provider (for example, Keycloak or Microsoft Entra ID), normalizes the required claims, and produces a DMT Identity Envelope.
- The envelope is the shared identity contract for DMT services and is used only to construct
IdentityContext. - The envelope is not an authentication credential. Authentication is completed entirely in the Trusted Identity Layer.
- The envelope is transported in a dedicated HTTP header:
DMT-Identity: <Identity Envelope>
This intentionally distinguishes it from the standard Authorization header and makes it clear that the envelope carries normalized identity, not an OAuth/OIDC access token.
The DMT Identity Envelope is an implementation-independent representation of normalized identity consumed by DMT services.
Initial representation:
{
"tenant": "customer-a"
}The envelope can evolve without affecting business logic:
{
"tenant": "customer-a",
"sub": "john.doe",
"roles": [
"device-admin"
],
"permissions": [
"device.read",
"device.power"
]
}To provide a compact, HTTP-header-safe, and implementation-neutral representation, the Identity Envelope is serialized as a Base64URL-encoded JSON document.
For example:
DMT-Identity: eyJ0ZW5hbnQiOiJjdXN0b21lci1hIiwic3ViIjoiam9obi5kb2UiLCJyb2xlcyI6WyJkZXZpY2UtYWRtaW4iXSwicGVybWlzc2lvbnMiOlsiZGV2aWNlLnJlYWQiLCJkZXZpY2UucG93ZXIiXX0DMT services process the envelope as follows:
Read DMT-Identity Header
│
▼
Base64URL Decode
│
▼
Parse JSON
│
▼
Construct IdentityContext
Although the Identity Envelope contains JSON data similar to a JWT payload, representing it as a JWT is not recommended.
A JWT implies a well-defined security model consisting of:
- A Header
- A Payload
- A Cryptographic Signature (or another integrity mechanism)
Since the DMT Identity Envelope is not intended to be independently authenticated or cryptographically verified by DMT services, the signature portion would either be omitted or require the use of the alg: none algorithm.
Using alg: none is discouraged because:
- It implies a JWT without cryptographic protection, which can be misleading.
- Many production JWT libraries intentionally reject or disable
alg: nonedue to historical security vulnerabilities and to prevent algorithm confusion attacks. - It introduces unnecessary coupling to JWT semantics, even though the Identity Envelope is simply a transport format for normalized identity.
A Base64URL-encoded JSON document avoids these issues while providing several advantages:
- Compact and safe for transport in HTTP headers.
- Simple to encode and decode using standard Base64URL and JSON libraries available in all major programming languages.
- Free from JWT-specific concepts such as issuers, audiences, algorithms, and signatures.
- Clearly communicates that the Identity Envelope is an internal DMT identity contract rather than an authentication token.
- Easily extensible as new normalized identity attributes are introduced.
The Trusted Identity Layer serves as the platform's authentication boundary and trust anchor.
It is responsible for:
- Authenticating external identities.
- Validating externally issued JWTs.
- Verifying token signature, issuer, audience, and expiration.
- Extracting provider-specific claims.
- Normalizing identity attributes into the DMT identity model.
- Producing the DMT Identity Envelope.
Both Console and RPS:
- Trust the Identity Envelope supplied by the Trusted Identity Layer.
- Do not independently authenticate the request or validate the original client JWT.
- Parse the Identity Envelope solely to construct the common
IdentityContext.
This establishes a trusted gateway model where authentication is centralized within the Trusted Identity Layer while identity transport is standardized across the DMT platform.
The Trusted Identity Layer is responsible for:
- Validating externally issued JWTs.
- Verifying signature, issuer, audience, and expiration.
- Extracting provider-specific claims.
- Normalizing identity attributes into the DMT identity model.
- Producing the DMT Identity Envelope.
- Injecting the Identity Envelope into the
DMT-IdentityHTTP header.
The Trusted Identity Layer may be implemented using API gateways or identity-aware proxies such as Kong, Traefik, Envoy, NGINX, Azure API Management, AWS API Gateway, or equivalent technologies.
Console implements lightweight request middleware that:
- Reads the
DMT-Identityheader. - Base64URL decodes the Identity Envelope.
- Parses the normalized identity attributes.
- Constructs the common
IdentityContext. - Enforces tenant isolation.
- Performs authorization.
The middleware is implemented as part of the Console request pipeline and is not intended as a runtime extensibility mechanism. Business logic remains completely independent of external Identity Providers, authentication mechanisms, and JWT formats.
RPS includes a lightweight Identity Middleware that acts as an adapter between the DMT Identity Envelope and the existing RPS request processing pipeline.
For each incoming request, the middleware:
- Reads the
DMT-Identityheader. - Base64URL decodes the Identity Envelope.
- Parses the normalized identity attributes.
- Constructs the existing request
IdentityContext. - Attaches the
IdentityContextto the request so it is available to downstream middleware and API handlers.
Authentication and identity normalization remain the responsibility of the Trusted Identity Layer. The Identity Middleware simply adapts the normalized identity into the existing RPS request context.
flowchart LR
C1["Client\nExternal JWT"] -->|"Bearer Token"| TIL1["Trusted Identity Layer\nValidate JWT\nNormalize Claims\nInject Identity Headers"]
TIL1 -->|"DMT Custom Headers\nX-DMT-Identity:\nX-DMT-Tenant:\n"| CON1["Console\nRead Headers\nBuild IdentityContext"]
TIL1 -->|"DMT Custom Headers\nX-DMT-Identity:\nX-DMT-Tenant:\n"| IM1["RPS Identity Middleware\nRead Headers\nBuild IdentityContext"]
IM1 --> RPS1["RPS Business Middleware\nAPI Handlers"]
flowchart LR
C[Client\nExternal JWT]
-->|Bearer Token| TIL[Trusted Identity Layer\nValidate JWT\nNormalize Claims\nIssue DMT Identity Token]
TIL -->|Bearer Token| Console[Console\nValidate Token\nBuild IdentityContext]
TIL -->|Bearer Token| IM[RPS Identity Middleware\nValidate Token\nBuild IdentityContext]
IM --> RPS[RPS Business Middleware\nAPI Handlers]
Console -.->|Token Validation| TIL
IM -.->|Token Validation| TIL
In this model, the Trusted Identity Layer (TIL) validates the incoming JWT issued by an external Identity Provider (for example, Keycloak or Microsoft Entra ID), extracts and normalizes the required identity claims, and injects them into downstream requests as trusted HTTP headers.
X-Tenant-ID
X-User-Roles
The original external JWT is not forwarded to DMT services.
Both Console and RPS consume the same normalized identity model while remaining independent of Identity Provider-specific token formats, claim structures, and validation mechanisms.
In this model, the Trusted Identity Layer (TIL) validates the incoming JWT issued by an external Identity Provider (for example, Keycloak or Microsoft Entra ID), extracts and normalizes the required identity claims, and issues a signed DMT Identity Token.
{
"tenant": "customer-a",
"sub": "john.doe",
"roles": [
"device-admin"
],
"permissions": [
"device.read",
"device.power"
]
}The DMT Identity Token becomes the common identity contract consumed by DMT services.
Each DMT service independently validates the DMT Identity Token before constructing the common IdentityContext.
In this model, the API Gateway is used solely for platform functions such as TLS termination, routing, and load balancing. It does not perform authentication, JWT validation, or identity normalization.
Instead, the original JWT issued by the external Identity Provider is forwarded unchanged to DMT services. Identity validation and normalization are implemented within the application through operator-supplied middleware.
For Console, the operator provides a compiled identity middleware that is linked into the Console build. This middleware validates the JWT, maps provider-specific claims into the DMT identity model, and constructs the common IdentityContext.
For RPS, the existing runtime middleware extensibility model is used to implement equivalent identity processing without requiring changes to the RPS core.
In this model, the API Gateway is not the authentication boundary.
Instead:
- The API Gateway forwards the original JWT unchanged.
- Each DMT service independently authenticates requests.
- Provider-specific claim normalization is implemented within each service.
- Each service constructs the common
IdentityContext.
This establishes an application-centric trust model, where authentication and identity normalization are the responsibility of the application rather than the platform.
The API Gateway is responsible only for platform networking functions, including:
- TLS termination
- Request routing
- Load balancing
- Rate limiting (optional)
It does not:
- Validate JWTs
- Normalize identity claims
- Modify requests
- Inject identity information
This allows operators to continue using their existing gateway configuration without customization.
Console includes an Operator Identity Middleware that is compiled into the Console binary.
The middleware is responsible for:
- Validating externally issued JWTs.
- Verifying token signature, issuer, audience, and expiration.
- Mapping provider-specific claims into the DMT identity model.
- Constructing the common
IdentityContext. - Enforcing tenant isolation and authorization.
Because the middleware is compiled into the application, supporting a different Identity Provider or claim mapping typically requires rebuilding the Console binary.
RPS continues to leverage its existing runtime middleware extensibility model.
Operators implement identity processing as an RPS middleware module responsible for:
- Validating externally issued JWTs.
- Mapping provider-specific claims into the DMT identity model.
- Constructing the common
IdentityContext. - Attaching the
IdentityContextto the request before it reaches downstream middleware and API handlers.
Existing RPS middleware continues to support customer-specific extensions such as:
- Request enrichment
- Request routing
- Auditing
- Tracing
- Business-specific processing
Unlike Console, identity processing can be modified without rebuilding RPS by deploying a new middleware module.
Both Console and RPS ultimately construct the same internal IdentityContext.
flowchart TD
A["Incoming Request\nAuthorization: Bearer <External JWT>"] --> B["Validate JWT"]
B --> C["Normalize Claims"]
C --> D["Construct IdentityContext"]
D --> E["Business Logic"]
Business logic remains completely independent of Identity Providers and consumes only the common IdentityContext.