Authorization
The movement endpoints are gated on the Camera.Operate
role, and requests arrive already carrying a bearer token. That token has to be minted
somewhere — and this API is where the login flow lives.
The one idea to hold on to
The API runs the OAuth2/OIDC flow against Azure AD B2C CIAM in two endpoints, delegating the
cryptography to the shared JWTService. It's a standard authorization-code exchange:
// GET /Authorization/login → build the authorize URL the browser is sent to
var result = _jwtService.GetFrontendAuthorizeRequest();
// GET /Authorization/callback?code=&state= → swap the code for tokens
return Ok(await _jwtService.GetFrontendTokensAsync(code, state));
login returns the CIAM authorize URL; the user signs in there; CIAM redirects back to
callback with a code; the API exchanges it for access and id tokens. Those tokens — and the
roles inside them, like Camera.Operate — are what the rest of the API authorizes against.
There are two halves to "authenticated request," and they live in different places. This API's
Authorization endpoints mint the tokens during login. The frontend's server-side proxy is
what attaches the bearer to every subsequent API call. If requests are arriving without a
bearer (and getting 401s), the problem is usually the proxy's injection, not this login flow —
check that the route is in the proxy's matcher before suspecting CIAM.
Wrapping up
Authorization is a thin CIAM authorization-code flow: login builds the authorize URL,
callback exchanges the code for tokens via the Infrastructure JWTService (certificate client
assertion, frontend flavor), and the roles in those tokens gate everything else. Minting happens
here; injecting the bearer onto later requests happens in the frontend proxy.
Next, the other direction — how the API pushes updates out and takes callbacks in: Real-Time & Engine Callbacks.