API Facade and Security

This document introduces the RestFrontage entry points for authenticating a client, viewing or modifying security, filtering OData objects, and using Razor tools.

For the conceptual model and decision rules, see Immersive Security Overview.

Authenticating an API Client

Get a token

POST {{baseUrl}}/api/Security/User/Authenticate
Content-Type: application/json

{
  "AccountName": "utilisateur",
  "Password": "mot-de-passe"
}

Alias accepted: POST /api/Security/Users/Authenticate.

Simplified answer:

{
  "Domain": "DC=Immersive, DC=GraphicStream, DC=fr",
  "Token": "eyJ...",
  "AuthenticatedUser": {
    "Identifier": 123,
    "DistinguishedNameValue": "AN=utilisateur, OU=Users, ..."
  }
}

The customer then transmits:

Authorization: Bearer {{token}}

Logins and password must be sent only over HTTPS.

Token cycle

Word and road Function
POST /api/Security/Token/Renew Renew a valid token
GET or POST /api/Security/Token/Validate Verify that the pipeline accepts the token
GET or POST /api/Security/Whoami Get the name of the current identity

Primary Security Endpoints

All roads below have the prefix /api/Security.

Rights Control and Administration

Word and road Usage Recommended Status
GET /Users/{askerId}/Rights/{flags}/SecurizedObjects/{type}/{objectId} Testing a mask on an object History; does not include shares
GET /Rights?securedObjectIdentifier=...&securedObjectTypeIdentifier=... Read an object's explicit rights Can be used for administration
POST /Rights Apply a collection of rights via ISecurityAdministrationService Recommended Writing Point
DELETE /Rights?rightIdentifiers=... Remove rights by ID History; to migrate to the central façade
GET /Permissions Read configured permissions Recommended for building an interface without hard-coded flags

Example of the application of a right:

POST {{baseUrl}}/api/Security/Rights
Authorization: Bearer {{token}}
Content-Type: application/json

[
  {
    "Identifier": 0,
    "DomainSecurityObjectIdentifier": 145,
    "SecurizedObjectIdentifier": 902,
    "SecurizedObjectType": 15,
    "AuthorizedFlags": 3,
    "DeniedFlags": 0
  }
]

Rules of POST /Rights :

  • the actor is always read from the authenticated context;
  • Cerebrate and root administrators can administer all rights;
  • otherwise the actor and the beneficiaries must belong to the current organization;
  • a beneficiary BuiltIn is protected;
  • the actor must be able to administer each target object;
  • flags must match the configured permissions;
  • AuthorizedFlags = 0 and DeniedFlags = 0 abolishes the corresponding duty;
  • Multiple queries for the same triplet are normalized before writing.

Error responses:

  • 400 - Invalid data or flags
  • 401 : absence of authenticated identity;
  • 403 : unauthorized actor or poor organization;
  • 409 : Data inconsistency or conflict, such as old duplicate rights.

Shares

Word and road Usage
POST /SharedAccess Create a share that AccessLinkIdentifier footnote one TinyUrl existing
POST /SharedAccess/Aggregate Explicitly create an aggregate and specify the TinyUrl at the root level
POST /SharedAccess/{grantIdentifier}/Revoke Revoke sharing without deleting the TinyUrl

Example of internal sharing for a week:

POST {{baseUrl}}/api/Security/SharedAccess/Aggregate
Authorization: Bearer {{token}}
Content-Type: application/json

{
  "TinyUrlIdentifier": "equipment-902-share",
  "Grant": {
    "BeneficiaryDomainSecurityObjectIdentifier": 245,
    "ExternalRecipientEmail": null,
    "ValidFromUtc": "2026-08-18T10:00:00Z",
    "ExpiresAtUtc": "2026-08-25T10:00:00Z",
    "Rights": [
      {
        "SecurizedObjectIdentifier": 902,
        "SecurizedObjectType": 18,
        "AuthorizedFlags": 1
      },
      {
        "SecurizedObjectIdentifier": 84,
        "SecurizedObjectType": 15,
        "AuthorizedFlags": 1
      },
      {
        "SecurizedObjectIdentifier": 31,
        "SecurizedObjectType": 48,
        "AuthorizedFlags": 1
      }
    ]
  }
}

For an external recipient, fill in ExternalRecipientEmail and leave BeneficiaryDomainSecurityObjectIdentifier à null. Exactly one of the two fields must be defined.

Simplified answer:

{
  "grantIdentifier": 12,
  "publicIdentifier": "...",
  "externalAccessToken": "retourné uniquement pour un partage externe",
  "tinyUrlIdentifier": "equipment-902-share",
  "tinyUrlPath": "/?TU=equipment-902-share",
  "externalAccessPath": "/Shared?token=...&tinyUrl=equipment-902-share"
}

The server does not infer any dependencies. Beholder, Forge or the Player must send the complete list of objects needed to open the target.

There is no dedicated REST route for the share list yet. This list is currently consumed by the partial Razor via GetSharedAccessGrantsAsync.

Minimum call of the sharing modal:

/Security/Modals/SharedAccess
    ?SecurizedObjectIdentifier={identifier}
    &SecurizedObjectType={type}
    &TinyUrlIdentifier={tinyUrlExistante}

Directory

The façade also exhibits the following families:

Family Main roads
Resolution GET /DomainObjects/{dnOuId}, POST /Discover
Navigation GET /DomainObjects/{dn}/Members, GET /Explorer/{dn}/Search/{criteria}
Affiliations GET, POST, PUT, DELETE /DomainObjects/{dn}/Membership
Group Members PUT, POST, DELETE /Groups/{dn}/Members
Hierarchy GET /DomainObjects/{dn}/GroupMembershipHierarchy
Expandable Fields GET, PUT, POST /DomainObjects/{dn}/Fields
Users POST /Users, PUT /Users, PATCH /Users({id}), DELETE /Users/{id}
Groups POST /Groups, PUT /Groups, PATCH /Groups({id}), DELETE /Groups/{id}
OR POST /OrganizationalUnits, PUT /OrganizationalUnits, PATCH /OrganizationalUnits({id}), DELETE /OrganizationalUnits/{id}
Organizational reconstruction POST /OrganizationalUnits/{id}/SubDomain/Rebuild

These directory routes are partly historical and do not all pass through ISecurityAdministrationService. Any new mutation must use the transversal façade or extend it.

Secure OData

ODataCrudController<TEntity> Enforces security only if the Immersive type has permissions configured.

For a secure type:

  • GET filters the IQueryable before the OData options are applied.
  • GET(key) and the navigations check the visibility of the parent;
  • PUT and PATCH require the controller's permission to edit;
  • DELETE requires the controller's permission to delete;
  • POST requires Cerebrate, a root administrator, or the Administrators The target subdomain.
  • After creation, the automatic rights are applied by the administration façade.
Entity set Type Reading Modification Deletion
/odata/Maps 15 ReadMap ModifyMap FullControlMap
/odata/Equipments 18 ReadEquipment ModifyEquipment FullControlEquipment
/odata/Workspaces 37 ReadWorkspace ModifyWorkspace FullControlWorkspace
/odata/SupervisionScopes 48 ReadSupervisionScope ModifySupervisionScope FullControlSupervisionScope

Example:

GET {{baseUrl}}/odata/SupervisionScopes?$filter=Name eq 'Yvetot'&$select=Identifier,Name
Authorization: Bearer {{token}}
Accept: application/json

The security filter and the OData filter are composed and then executed by the business base. The controller does not have to download the entire collection before filtering.

Useful RestFrontage Pages

Main entrances

Path Function Access
/Security Current Domain Dashboard Authenticated user
/Security/Explorer Browse ORs, users, groups, and devices Authenticated user
/Security/UsersAndGroups Find and administer users and groups Authenticated user; mutations controlled by their handlers
/Security/RightsTester Explaining an effective right Authenticated user and current organization
/Security/Tools Security audits and repairs Cerebrate only

Rights Tester

The tester allows you to choose:

  1. a user or group;
  2. A recognized object type.
  3. An object belonging to the current organization.
  4. A permission configured for this type.

It produces a AuditAccess which details the membership paths that have allowed or denied access. The catalog detects types from the DbSet<TEntity> whose entity implements IIdentifiedObject and has a ImmersiveObjectAttribute.

Current limits: Selection capped at 5,000 objects per type and no internal shares in the report.

Cerebrate Tools

The page /Security/Tools is accessible only by Cerebrate. It should not be used as a common administration interface.

Singleness of Rights

The tool displays:

  • the number of rights;
  • duplicate groups;
  • the presence of the unique SQL index.

The current manual cleanup keeps the most recent row of the chosen group. Migration 20260815_EnforceUniqueRights follows a more conservative strategy: it first merges all allowed and forbidden flags before removing the old lines.

Structure of organizations

The audit verifies for each organization:

  • ORs Groups, Users and Devices ;
  • Groups Administrators, Users and Sharers ;
  • The user {Organisation}_Admin ;
  • Standard memberships
  • conventional permission groups already recognized.

Reparation calls for EnsureSubDomainDefaultsAsync and preserves existing data.

Automatic fees

The audit compares the expected and registered entitlements for:

  • maps;
  • equipment;
  • workspaces;
  • the scope of supervision.

It can repair an object or a selection. The repair only adds the missing auto flags.

Points of vigilance and tightening to be expected

High priority

  1. GET /api/Security/ResetDomain currently carries [AllowAnonymous]. Even if it doesn't change the rights, it causes a global reload and invalidation; it must be protected or moved to the recovery console.
  2. DELETE /api/Security/Rights deletes directly in SecurityModel without going through the authorization of ISecurityAdministrationService. It must be replaced by POST /Rights with zero flags or by a dedicated central method.
  3. Internal shares are not yet viewed by ObjectSecurityService. They are persisted but do not yet provide access in OData.
  4. The historic test HaveRight and Razor tester use SecurityUtils directly and do not see the shares.

Consistency priority

  1. Gradually centralize the transfer of users, groups, OR and memberships.
  2. Add an authenticated organization selection route that is suitable for stateless Bearer customers, or include a controlled organization context in the API contract.
  3. Expose a share list route if WebGL clients need to administer shares without Razor partisanship.
  4. Extend automatic entitlement auditing when new types are plugged into the pipeline.
  5. Eventually retire historical aliases after client migration.

Add a new secure type

To extend the façade without creating a service by type:

  1. declare the type in ImmersiveObjectType ;
  2. Apply ImmersiveObjectAttribute on the entity;
  3. register its Permission in the field and the instant ObjectsToPermissions ;
  4. derive the controller fromODataCrudController<TEntity> ;
  5. provide ReadPermission, UpdatePermission and DeletePermission ;
  6. inject existing cross-cutting services;
  7. ensure that ISubDomainService can find the organization of the entity;
  8. add its RightsDefaultPattern if necessary;
  9. Add the type to the automatic entitlement audit.
  10. Test read, create, edit, delete, ban, Cerebrate, and multi-instance.

Reference Files

| Subject | File | |---|---| | REST Controller | Controllers/SecurityController.cs | | Session Controller/Organization | Controllers/SessionController.cs | | JWT Pipeline | Commons/Immersive.RestFrontage.Components/Security/TokenParserMiddleware.cs, TokenCheckMiddleware.cs | | Generic OData Controller | corporate/Commons/GraphicStream.Server.Components/Controllers/ODataCrudController.cs | | Tester Catalog | Security/SecurizedObjectCatalog.cs | | Tester | Pages/Security/RightsTester.cshtml.cs | | Tools | Pages/Security/Tools | | Sharing modal | Pages/Security/Modals/SharedAccess.cshtml and .cshtml.cs | | External Page | Pages/Shared/Index.cshtml and .cshtml.cs |