> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Enforce a user permission

> Enforces a permission for the Bearer token subject against a resource and action. A denied permission is returned as 200 with authorized=false, not 403. A 403 means the caller IP is outside the IP allowlist (AUT-0021). A token whose credential no longer resolves is answered 401, not a server error, and retrying will not help: AUT-1011 when its application was deleted, AUT-1012 when the partner it belongs to was. When a Lerian product that serves a partner's request calls another and sends the partner's token as actorToken, the request is authorized only when both tokens are, and a refusal by the partner is still a 200 with authorized=false and a reason starting with actor_. A partner granted nothing in the product is checked only for its credential, tenant, state and validity window, and its IP allowlist is not applied on this call. A product route that lets a partner leave its own party out of the request sends resolve: the partner's single value of each listed dimension is decided and returned in resolved, and two or more values are refused as reason=ambiguous. When the authorization server cannot be reached, is too slow to answer, or is failing, the answer is 503 AUT-0033: nothing about the request was wrong, and it may be retried later.



## OpenAPI

````yaml /pt/openapi/v3-current/AM-auth.yaml post /v1/authorize
openapi: 3.1.0
info:
  contact:
    name: Lerian Studio
    url: https://lerian.studio
  description: OpenAPI 3.1 surface for the Access Manager auth component.
  license:
    name: Lerian Studio General License
  title: Access Manager Auth API
  version: v1
servers:
  - url: https://auth.sandbox.lerian.net
security: []
tags:
  - description: >-
      OAuth2 token issuance: request an access token, refresh it, and log out.
      Public issuer endpoints.
    name: OAuth
  - description: >-
      Single sign-on through the tenant's identity provider: discover how an
      email signs in, then start the login. Public, called by the browser before
      login.
    name: SSO
  - description: >-
      Multi-factor authentication challenge and verification during the login
      flow. Public (identity is carried by the MFA token, not a Bearer token).
    name: MFA
  - description: >-
      Token-secured routes: enforce a permission, list the caller's permissions,
      and fetch OIDC user info. Require a Bearer token, validated in the use
      case.
    name: User Permission
paths:
  /v1/authorize:
    post:
      tags:
        - User Permission
      summary: Enforce a user permission
      description: >-
        Enforces a permission for the Bearer token subject against a resource
        and action. A denied permission is returned as 200 with
        authorized=false, not 403. A 403 means the caller IP is outside the IP
        allowlist (AUT-0021). A token whose credential no longer resolves is
        answered 401, not a server error, and retrying will not help: AUT-1011
        when its application was deleted, AUT-1012 when the partner it belongs
        to was. When a Lerian product that serves a partner's request calls
        another and sends the partner's token as actorToken, the request is
        authorized only when both tokens are, and a refusal by the partner is
        still a 200 with authorized=false and a reason starting with actor_. A
        partner granted nothing in the product is checked only for its
        credential, tenant, state and validity window, and its IP allowlist is
        not applied on this call. A product route that lets a partner leave its
        own party out of the request sends resolve: the partner's single value
        of each listed dimension is decided and returned in resolved, and two or
        more values are refused as reason=ambiguous. When the authorization
        server cannot be reached, is too slow to answer, or is failing, the
        answer is 503 AUT-0033: nothing about the request was wrong, and it may
        be retried later.
      operationId: enforcePermission
      parameters:
        - description: >-
            Bearer access token to enforce. The request is rejected with 401
            (AUT-0006) when absent.
          in: header
          name: Authorization
          schema:
            description: >-
              Bearer access token to enforce. The request is rejected with 401
              (AUT-0006) when absent.
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnforcePermissionInput'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EnforcePermissionResult'
          description: OK
        '422':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Unprocessable Entity
        '500':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Internal Server Error
        '503':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Service Unavailable
        default:
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Detail'
          description: Error
      security:
        - BearerAuth: []
components:
  schemas:
    EnforcePermissionInput:
      additionalProperties: false
      properties:
        action:
          description: The operation being performed on the resource.
          examples:
            - post
          type: string
        actorToken:
          description: >-
            The partner's own access token, exactly as the calling Lerian
            product received it, sent when that product calls this one while
            serving a partner's request. The Bearer token then belongs to the
            calling product, and the request is authorized only when BOTH are:
            the calling product by its own permissions, and the partner by the
            rules it was granted for this product. A partner granted nothing in
            this product is checked here only for its credential, tenant, state
            and validity window, and the partner's IP allowlist is not applied,
            since this call comes from the calling product, not from the
            partner. When the partner refuses, authorized is false and reason
            starts with "actor_": actor_tenant (the partner belongs to another
            tenant), actor_suspended or actor_expired (the partner is no longer
            honoured), actor_invalid (not an active partner credential, or its
            application or partner was deleted), actor_permission or actor_scope
            (outside the partner's grant). Optional.
          type: string
        attributes:
          additionalProperties:
            type: string
          description: >-
            Instance identifiers the calling product extracted from the request
            being authorized, keyed by the product's declared scope field
            (midaz: "organizationId", "ledgerId"). Optional and additive: a
            request without it is decided exactly as before. Consumed only for a
            credential bound to a partner; accepted and ignored for every other
            credential.
          examples:
            - organizationId: 00000000-0000-0000-0000-000000000000
          type: object
        clientIp:
          description: >-
            Originating caller IP forwarded by lib-auth for tenant IP-allowlist
            enforcement. Optional, and honoured ONLY when the calling service
            reaches this API from a network the platform declares as its own;
            from any other caller the field is ignored.
          examples:
            - 203.0.113.7
          type: string
        product:
          description: >-
            Product that owns the route, forwarded by lib-auth for user-flow
            isolation. Optional.
          examples:
            - midaz
          type: string
        resolve:
          description: >-
            Scope dimensions (catalog field names) the calling product asks this
            API to fill in from the partner's own scope, for a route that lets a
            partner leave its own party out of the request. For each one the
            request does not name, a partner holding exactly one value of it in
            this product is decided as that value, returned in resolved. It is
            refused as reason=ambiguous when the partner holds two or more
            values, and as reason=scope when it holds none, the request also
            names it in attributes, the product's catalog does not declare it,
            or the resource is that dimension's own collection or one it covers;
            a grant that does not hold the action on the resource refuses as
            reason=permission first. Refused as actor_scope together with
            actorToken. Consumed only for a credential bound to a partner;
            accepted and ignored for every other credential, whose answer then
            carries no resolved. Optional.
          examples:
            - - originador
          items:
            type: string
          type:
            - array
            - 'null'
        resource:
          description: The resource being accessed (e.g. "organizations", "ledgers").
          examples:
            - ledger
          type: string
        sub:
          description: >-
            Subject to enforce, forwarded by lib-auth (e.g.
            "admin/ledger-editor-role" for applications). Optional.
          examples:
            - admin/ledger-editor-role
          type: string
      required:
        - resource
        - action
      type: object
    EnforcePermissionResult:
      additionalProperties: false
      properties:
        authorized:
          description: >-
            Whether the subject is authorized for the resource+action. A false
            value is still returned as HTTP 200, not 403.
          examples:
            - true
          type: boolean
        reason:
          description: >-
            Why the request was denied. Present only when authorized is false
            and the credential is bound to a partner, or the partner named by
            actorToken refused (the actor_ values). "suspended" and "expired"
            mean the partner credential itself is no longer valid and the caller
            should answer 401; "permission" and "scope" stay the 403 a denial is
            today and are for logs only — never surface which axis failed to the
            end caller. "ambiguous" answers a request with resolve: the partner
            holds two or more values of a dimension it asked resolved, so the
            request has to name one.
          enum:
            - permission
            - scope
            - ambiguous
            - suspended
            - expired
            - actor_tenant
            - actor_invalid
            - actor_permission
            - actor_scope
            - actor_suspended
            - actor_expired
          examples:
            - scope
          type: string
        resolved:
          additionalProperties:
            type: string
          description: >-
            One value per dimension the request asked in resolve: the partner's
            single value of it. Present only when authorized is true and the
            request carried resolve; the calling product acts as this party.
          examples:
            - originador: 00000000-0000-0000-0000-000000000000
          type: object
        timestamp:
          description: Server time at which the decision was made (RFC 3339).
          examples:
            - '2024-01-15T09:30:00Z'
          format: date-time
          type: string
      required:
        - authorized
        - timestamp
      type: object
    Detail:
      additionalProperties: true
      properties:
        code:
          description: >-
            Stable, machine-readable domain error code scoped to the emitting
            service (format: <SERVICE>-NNNN).
          type: string
        detail:
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          examples:
            - Property foo is required but is missing.
          type: string
        errors:
          description: Optional list of individual error details
          items:
            $ref: '#/components/schemas/ErrorDetail'
          type:
            - array
            - 'null'
        instance:
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          examples:
            - https://example.com/error-log/abc123
          format: uri
          type: string
        status:
          description: HTTP status code
          examples:
            - 400
          format: int64
          type: integer
        title:
          description: >-
            A short, human-readable summary of the problem type. This value
            should not change between occurrences of the error.
          examples:
            - Bad Request
          type: string
        type:
          default: about:blank
          description: A URI reference to human-readable documentation for the error.
          examples:
            - https://example.com/errors/example
          format: uri
          type: string
        upstream:
          $ref: '#/components/schemas/Upstream'
          description: >-
            RFC 9457 extension member: the error a proxied third-party provider
            reported. Absent unless the emitting service explicitly surfaced
            one.
      type: object
    ErrorDetail:
      additionalProperties: false
      properties:
        location:
          description: >-
            Where the error occurred, e.g. 'body.items[3].tags' or
            'path.thing-id'
          type: string
        message:
          description: Error message text
          type: string
        value:
          description: The value at the given location
      type: object
    Upstream:
      additionalProperties: false
      properties:
        code:
          description: The upstream provider's own error code, verbatim.
          examples:
            - E4001
          type: string
        message:
          description: >-
            The upstream provider's own error message, verbatim (bounded, never
            its raw response body).
          examples:
            - account not found at provider
          type: string
      type: object
  securitySchemes:
    BearerAuth:
      bearerFormat: JWT
      description: JWT bearer token issued by the identity provider.
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.