Skip to content

Treat Entra service principals as first-class SimpleChat principals for backend API access #1029

Description

@paullizer

Summary

Treat approved Microsoft Entra service principals and managed identities as first-class, non-human SimpleChat principals for direct backend API access.

A service principal should authenticate to the same SimpleChat Entra resource/audience that users access, then participate in the same downstream authorization model as a user: personal ownership, group and public-workspace membership, workspace roles, direct shares, feature gates, object-level access checks, and activity logging. It does not use the browser UI, but an API operation performed by a service principal should execute through the same authorization-aware service layer and have the same effect as the equivalent operation performed by an authorized user.

This replaces the idea of SimpleChat issuing a separate long-lived API token or maintaining a parallel per-API grant system. Entra remains the token issuer. SimpleChat registers and governs the non-human principal, while existing SimpleChat roles and resource relationships decide what it may do.

User Value

This enables applications and automation to use SimpleChat without impersonating a human or receiving a special, weakly governed API key. Examples include:

  • An application invoking an agent or starting and monitoring a workflow.
  • A managed identity creating and using its own chats, agents, workflows, or documents.
  • A group owner assigning a service principal the same Owner, Admin, DocumentManager, or User role available to a human, subject to the same role-change rules.
  • A public-workspace owner assigning the service principal an existing workspace role.
  • A user sharing a document with a service principal; the service principal authenticates through the API, accepts or declines the pending share, and can use the document only after approval.
  • A service principal participating in collaboration features where an equivalent user principal is supported.
  • Azure API Management fronting the API for network controls, quotas, subscriptions, or partner products while Entra and SimpleChat remain the authentication and authorization authorities.

Core Design

One Principal Model

Introduce a shared authenticated-principal abstraction with at least:

  • principal_id: stable SimpleChat identity key.
  • principal_type: user or service_principal.
  • Entra tenant ID and object ID.
  • Application/client ID for service principals.
  • Display name and status.
  • Human owner/contact name and email for a service principal; these describe accountability and are not the principal's login identity.
  • Token roles and relevant authentication metadata.

Existing users remain backward compatible. Do not create fake user profiles, fake email addresses, or browser sessions for service principals. Where existing records use user_id, introduce a compatible principal-aware path and migrate schemas only where necessary. New or changed membership/share records should identify the principal type so profile lookup, display, notifications, and audit behavior remain unambiguous.

Same Authentication Boundary

  • Human browser users continue through the existing Entra sign-in and session flow.
  • A service principal or managed identity obtains a normal short-lived Entra OAuth 2.0 access token using client credentials, workload identity federation, certificate credentials, or managed identity.
  • Service-principal access tokens use the same configured SimpleChat API audience, issuer/tenant policy, signature validation, lifetime validation, and application-role infrastructure as other accepted Entra tokens.
  • SimpleChat does not mint, display, store, renew, rotate, or recover bearer-token secrets.
  • Access-token lifetime is governed by Entra and should not become a separate SimpleChat concept. The caller reacquires tokens through Entra just as a client reacquires any expired access token.
  • Service-principal requests establish a request-scoped principal context, not a Flask browser session.
  • The current ExternalApi application role may remain an admission requirement, but it must not bypass SimpleChat registration, roles, memberships, shares, feature gates, or object-level authorization.

Same Authorization Structure

After authentication, use the same authorization decisions for users and service principals:

  • A principal can own and operate on its own personal resources where the feature supports personal scope, including conversations/chats, documents, agents, workflows, and related run history.
  • Group and public-workspace owners/admins can add a registered service principal through the existing membership experience and assign the same available roles, with the same restrictions, warnings, transfer rules, and audit requirements as for a user.
  • Direct document and other supported resource shares can target a registered service principal.
  • If the existing share requires recipient approval, the service principal must call the equivalent backend approval/decline API before access becomes active. It must not auto-approve merely because it is an application.
  • Conversation participation, assigned knowledge, and other relationship-based access should use the same principal-aware checks where those features support users today.
  • Caller-supplied group, workspace, conversation, message, document, agent, workflow, run, or share IDs remain untrusted. Every operation must revalidate the exact target relationship at the data-access boundary.
  • A service principal receives no implicit global access and cannot act as another user. Its effective permissions are the intersection of its Entra admission role, SimpleChat status, feature flags, workspace/resource relationships, assigned role, and operation-specific authorization.

Backend API Surface

The target is backend API parity with an equivalently authorized user, not a separate integration-only API with different business rules.

  • Classify routes explicitly by supported principal types, for example user, service_principal, or both.
  • Frontend/template/session-management routes are always human-browser only.
  • Backend routes may become service-principal compatible only after their session dependencies, identity assumptions, response schemas, and object-level checks use the shared principal context.
  • Maintain a deny-by-default inventory of service-principal-compatible backend operations. This inventory is a route-readiness/security classification, not a per-service-principal permission list that duplicates workspace RBAC.
  • Do not infer compatibility from /api, Swagger discovery, HTTP method, or the presence of @login_required.
  • Prefer shared authorization-aware service functions used by both browser routes and API-principal routes so chat, agent, workflow, document, and collaboration behavior does not fork into separate implementations.
  • Version and document the externally supported contract. Existing /external/* routes should be inventoried and migrated to the principal model or explicitly documented as legacy.
  • Initial implementation and validation must include chats, agent invocation, workflow execution, asynchronous run status/results, group/public role assignment, direct document sharing, and recipient share approval.
  • Long-running or retryable operations should support run IDs and idempotency keys so client retries do not duplicate chats, messages, workflows, or other mutations.

Security Center: Service Principals

Add an admin-only Service Principals or API Access area under Security Center.

Admins can register and approve an existing Entra service principal or managed identity by supplying or resolving:

  • Display name.
  • Required purpose/business justification.
  • Required human owner/contact name and email.
  • Tenant ID.
  • Application/client ID.
  • Service-principal object ID.
  • Optional start and access-review/expiration date.
  • Enabled, disabled, expired, or revoked status.
  • Created/updated/approved by and timestamps.
  • Last successful authentication, last denied request, and recent activity summary.

The page must support validation, registration, editing accountability metadata, disablement, revocation, renewal of the SimpleChat registration where expiration is used, and archival. Disablement or revocation takes effect on the next request even if an Entra token remains valid.

This page manages SimpleChat recognition and status, not credentials. It must never request, reveal, copy, or persist an access token, client secret, certificate private key, or federated credential. Non-secret identifiers may be displayed with clear labels and safe truncation.

Provide a principal details view showing its personal resources, group/public memberships and roles, incoming shares and approval state, last use, and audit history. Human owners may be linked by immutable Entra object ID if desired, but owner email alone is not an authorization relationship.

Membership, Sharing, and UI Integration

  • Registered service principals appear in admin, group, public-workspace, collaboration, and share pickers only where that resource supports non-human principals.
  • Display a clear Service principal or Managed identity badge so users never mistake an application for a person.
  • Group/public owners and admins can assign and remove roles using the same workflows and policy checks used for users.
  • High-privilege assignments such as Owner or Admin show the same warnings and confirmation requirements, with any additional non-human-owner warning identified by threat review.
  • Personal document owners can share with a service principal. Pending, accepted, declined, revoked, and removed states follow the same lifecycle as user shares.
  • Because the service principal has no browser UI, every action it must take itself, including listing and accepting pending shares, must have a documented compatible backend API.
  • Notifications intended only for a human UI should not be silently written to an unusable profile. Expose actionable pending state through API and notify the registered human owner where existing notification infrastructure safely supports it.

Swagger and Documentation

  • Keep Swagger enablement admin-controlled; direct API authentication must not depend on Swagger being enabled.
  • Mark each operation with its supported principal types and authentication requirements. The general OpenAPI document must not imply that bearer authentication makes a frontend or session-only route callable.
  • When Swagger is enabled, link between General Swagger settings/documentation and Security Center Service Principals.
  • Allow an administrator/developer to paste a short-lived Entra access token into Swagger for testing supported backend APIs, but never collect or persist a client secret in Swagger UI.
  • Document token acquisition through managed identity, workload identity federation, certificates, and client credentials, with curl, PowerShell, and SDK examples.
  • Document service-principal registration, group/public role assignment, personal-resource ownership, document sharing and approval, revocation, troubleshooting, and audit review.
  • Explain optional APIM placement. APIM subscription identifiers may add product governance, but they do not replace Entra authentication or SimpleChat authorization.
  • Explain that PIM can govern eligible Entra or SimpleChat administrative role assignments where supported; it does not issue SimpleChat tokens.

Audit and Operations

Use the existing activity-log pipeline for service-principal actions, extending it with principal-aware fields rather than creating an unrelated log stream.

Record:

  • Service principal registered, approved, changed, disabled, revoked, renewed, expired, and archived.
  • Group/public membership and role assignments/removals.
  • Resource shares offered, accepted, declined, revoked, or removed.
  • Successful and denied API requests.
  • Chat/message, document, agent, workflow, and other domain actions using the same activity types as users, with actor principal type included.
  • Agent/workflow runs and terminal outcomes.

Audit records should include principal ID/type, tenant ID, application ID, service-principal object ID, human administrative actor where applicable, operation/route ID, target workspace/resource IDs, result, HTTP status, correlation/request ID, and timestamp. Never record raw tokens, authorization headers, credentials, or sensitive request/response content. Track last_used efficiently without introducing a hot write on every request.

Rate, Safety, and Lifecycle Controls

  • Apply the same feature, content-safety, approval, retention, and policy controls that apply to equivalent user operations.
  • Add per-principal rate, concurrency, payload-size, and execution limits suitable for automation, especially for model-backed chat, agent, and workflow calls.
  • Support a global service-principal API kill switch plus per-principal disable/revoke controls.
  • Return consistent 401, 403, 404, 409, 429, and asynchronous 202 behavior without exposing whether inaccessible resources exist.
  • Define behavior for disabled/deleted Entra service principals, removed app roles, expired SimpleChat registrations, owner departure, and orphaned resources.
  • Define transfer or cleanup workflows for personal resources owned by a service principal before it is archived or permanently removed.

Acceptance Criteria

  • A threat model and architecture decision record define user-session, delegated-user, service-principal, managed-identity, Easy Auth, direct-origin, and APIM trust boundaries.
  • Bearer validation enforces algorithm, signature, issuer, tenant, audience, expiration, not-before time, signing-key refresh, application identity, and required Entra app role.
  • Service-principal tokens have normal Entra access-token lifetime behavior; SimpleChat issues and stores no API token or refresh-token secret.
  • A shared request principal supports user and service_principal without creating a fake user or browser session.
  • Existing users and stored membership/share records remain backward compatible or have a documented migration.
  • A registered, enabled service principal can own and use supported personal chats, documents, agents, workflows, and related resources under its own principal ID.
  • Group owners/admins can add a registered service principal and assign/remove every role allowed by the existing group policy; authorization checks treat the assignment consistently with a user.
  • Public-workspace owners/admins can add a registered service principal and assign/remove every role allowed by the existing public-workspace policy.
  • A user can share a document with a service principal; access remains pending until the service principal authenticates and accepts it through the API, and decline/revoke/remove behavior matches user sharing.
  • Supported collaboration and relationship-based features resolve service-principal membership and shares without requiring a human profile record.
  • Effective access is determined by the existing role, ownership, membership, sharing, feature, and object-level checks, with no parallel per-API permission model that can drift from them.
  • Backend routes explicitly declare supported principal types; frontend, template, login, callback, session-management, and unclassified routes reject service-principal access.
  • Service-principal compatibility is not inferred from an /api prefix, Swagger entry, or HTTP method.
  • Initial end-to-end coverage includes chat/message creation, agent invocation, workflow execution and status/results, group/public role use, document listing/use, and share acceptance.
  • Equivalent user and service-principal operations call shared business and authorization services and produce equivalent domain outcomes.
  • Every caller-supplied object ID is rebound to an authorized principal/workspace relationship before data access or mutation.
  • Long-running and retried mutations support asynchronous run IDs and idempotency where duplication is possible.
  • Security Center lets admins validate, register, inspect, disable, revoke, renew where configured, and archive a service principal without handling its credentials.
  • Service principals are visibly distinguished from users in membership/share pickers and activity views.
  • Disabling/revoking a principal or using the global kill switch prevents its next request even if its Entra token remains valid.
  • Existing activity logs record service-principal domain actions with actor type and immutable Entra identifiers, and lifecycle/role/share changes are fully auditable.
  • No token, secret, private key, credential, or full authorization header is persisted or rendered by SimpleChat.
  • Rate, concurrency, payload, safety, retention, and feature controls apply to service principals and cannot be bypassed through direct API access.
  • Swagger remains optional, accurately marks supported principal types, links to Security Center, and can test with a caller-supplied short-lived token without storing it.
  • Setup documentation covers Entra configuration, app-role assignment, managed identities, workload identity federation, certificates/client secrets, SimpleChat registration, roles, sharing, token acquisition, APIM, PIM, revocation, and examples.
  • Existing /external/* endpoints are migrated or explicitly classified, with no privilege broadening.
  • Route-policy tests prove that no frontend or unclassified backend route accepts a service-principal token.
  • Security tests cover malformed/expired tokens, wrong issuer/tenant/audience/role/app/object ID, unregistered/disabled/revoked principals, cross-principal and cross-workspace access, pending/unapproved shares, stale roles, object enumeration, throttling, and duplicate retries.
  • Functional tests compare user and service-principal outcomes for the same authorized operations and verify activity/audit records.

Non-Goals

  • SimpleChat-issued API keys, personal access tokens, refresh tokens, or recoverable bearer secrets.
  • Converting an app-only token into a Flask browser session or allowing a service principal to render/use frontend pages.
  • Treating the service principal as, or allowing it to impersonate, a human user.
  • A separate per-integration operation grant model that duplicates existing SimpleChat roles and resource authorization.
  • Automatic creation of Entra app registrations, client secrets, certificates, federated credentials, or managed identities through high-privilege Microsoft Graph/Azure permissions.
  • Deploying APIM or configuring PIM automatically; document supported patterns instead.

Related Work

Implementation Notes

Relevant current areas include functions_authentication.py, swagger_wrapper.py, group/public authorization helpers, personal document sharing, route-policy tests, workflow and agent runners, chat routes, activity logging, and the admin/security UI. Today get_current_user_id() reads only from the Flask session, accesstoken_required checks only the coarse ExternalApi role, and several membership/share records combine identity IDs with human profile fields. The implementation should centralize principal resolution first, then migrate backend route families incrementally while preserving one authorization and business-logic path.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestsecurity_improvementThis issue results in an improvement to security

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Pending Evaluation

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions