components:
  schemas:
    AccessTokenForm:
      additionalProperties: false
      properties:
        client_id:
          description: Client identifier. Overridden by HTTP Basic credentials when they are sent.
          type: string
        client_secret:
          description: Client secret. Overridden by HTTP Basic credentials when they are sent.
          type: string
        code:
          description: SSO code, for the sso_code grant.
          type: string
        grant_type:
          description: OAuth2 grant type. sso_code is accepted but its state and code_verifier cannot be sent in this format; use the JSON format for it.
          enum:
            - password
            - client_credentials
            - sso_code
          type: string
        password:
          description: Password, for the password grant.
          type: string
        username:
          description: Username, for the password grant.
          type: string
      required:
        - grant_type
      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
    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
    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
    HTTPError:
      additionalProperties: false
      properties:
        availableMethods:
          description: "Present on AUT-0019: the factors the person can enroll (app, email)."
          items:
            type: string
          type:
            - array
            - "null"
        code:
          description: Stable, machine-readable error code (AUT-NNNN). Branch on this, not on the message.
          examples:
            - AUT-0009
          type: string
        fields:
          additionalProperties: {}
          description: "Present on body validation errors: each offending member mapped to what is wrong with it (AUT-0001 missing, AUT-0009 invalid) or, for AUT-0003, to the unexpected value that was sent."
          type: object
        message:
          description: Human-readable explanation of this occurrence.
          type: string
        mfaToken:
          description: "Present on AUT-0019: the enrollment-only token for POST /v1/login/mfa/setup and /confirm."
          type: string
        title:
          description: Short, human-readable summary of the error class.
          examples:
            - Bad Request
          type: string
      type: object
    MFAChallengeInitiatedResponse:
      additionalProperties: false
      properties:
        message:
          description: Human-readable acknowledgement that the challenge was dispatched.
          examples:
            - MFA challenge initiated
          type: string
      required:
        - message
      type: object
    MFAChallengeInput:
      additionalProperties: false
      properties:
        mfaToken:
          description: Short-lived MFA session token issued when a login requires MFA.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
        mfaType:
          description: Use email to send a verification code. The app value is accepted but does not send a code; authenticator apps generate passcodes locally.
          enum:
            - app
            - email
          examples:
            - app
          type: string
      required:
        - mfaToken
        - mfaType
      type: object
    MFAChallengeResponse:
      additionalProperties: false
      properties:
        availableMethods:
          examples:
            -   - app
                - email
          items:
            type: string
          type:
            - array
            - "null"
        mfaRequired:
          examples:
            - true
          type: boolean
        mfaToken:
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
        preferredMethod:
          examples:
            - app
          type: string
      required:
        - mfaRequired
        - mfaToken
        - availableMethods
        - preferredMethod
      type: object
    MFAConfirmInput:
      additionalProperties: false
      properties:
        mfaToken:
          description: The enrollment-only token of a 401 AUT-0019 refusal.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
        mfaType:
          description: The factor set up.
          enum:
            - app
            - email
          examples:
            - app
          type: string
        passcode:
          description: The one-time passcode (6 numeric digits) read off the new factor.
          examples:
            - "******"
          type: string
      required:
        - mfaToken
        - mfaType
        - passcode
      type: object
    MFASetupInput:
      additionalProperties: false
      properties:
        mfaToken:
          description: The enrollment-only token of a 401 AUT-0019 refusal.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
        mfaType:
          description: "The factor to enroll: one of the availableMethods of the AUT-0019 refusal."
          enum:
            - app
            - email
          examples:
            - app
          type: string
      required:
        - mfaToken
        - mfaType
      type: object
    MFASetupResponse:
      additionalProperties: false
      properties:
        mfaType:
          examples:
            - app
          type: string
        recoveryCodes:
          description: The recovery code to show once and ask the person to keep.
          items:
            type: string
          type:
            - array
            - "null"
        secret:
          description: The authenticator secret for manual entry. App only.
          examples:
            - JBSWY3DPEHPK3PXP
          type: string
        url:
          description: The otpauth URI to render as a QR code. App only.
          examples:
            - otpauth://totp/Lerian:ana?secret=JBSWY3DPEHPK3PXP
          type: string
      required:
        - mfaType
        - recoveryCodes
      type: object
    MFAVerifyInput:
      additionalProperties: false
      properties:
        mfaToken:
          description: Short-lived MFA session token issued when a login requires MFA.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
        mfaType:
          description: The MFA method being verified.
          enum:
            - app
            - email
          examples:
            - app
          type: string
        passcode:
          description: One-time passcode (6 numeric digits) for TOTP/email. Provide either passcode or recoveryCode.
          examples:
            - "******"
          type: string
        recoveryCode:
          description: A single-use recovery code, as an alternative to a passcode. Provide either passcode or recoveryCode.
          examples:
            - "******"
          type: string
      required:
        - mfaToken
        - mfaType
      type: object
    OAuth2Token:
      additionalProperties: false
      properties:
        accessToken:
          description: The issued OAuth2 access token (JWT).
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        expiresIn:
          description: Access token lifetime in seconds.
          examples:
            - 3600
          format: int64
          type: integer
        idToken:
          description: The OIDC ID token (JWT).
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        refreshToken:
          description: The refresh token to obtain a new access token.
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        scope:
          description: Space-delimited scopes granted to the token.
          examples:
            - openid profile email
          type: string
        tokenType:
          description: The token type; always "Bearer".
          examples:
            - Bearer
          type: string
      required:
        - accessToken
        - tokenType
        - expiresIn
        - refreshToken
      type: object
    OAuth2TokenStandardResponse:
      additionalProperties: false
      properties:
        access_token:
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        expires_in:
          examples:
            - 3600
          format: int64
          type: integer
        id_token:
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        refresh_token:
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        scope:
          examples:
            - openid profile email
          type: string
        token_type:
          examples:
            - Bearer
          type: string
      required:
        - access_token
        - token_type
        - expires_in
      type: object
    PasskeyBeginInput:
      additionalProperties: false
      properties:
        email:
          description: The e-mail of the person signing in. The tenant is resolved from it.
          examples:
            - ana@acme.com
          format: email
          maxLength: 254
          minLength: 3
          type: string
      required:
        - email
      type: object
    PasskeyBeginResponse:
      additionalProperties: false
      properties:
        options:
          description: The WebAuthn request options (publicKey) to pass to navigator.credentials.get, exactly as the identity provider wrote them.
        passkeyToken:
          description: Short-lived token naming this login attempt. Send it back to /v1/login/passkey/finish within 5 minutes; it works once.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          type: string
      required:
        - passkeyToken
        - options
      type: object
    PasskeyFinishInput:
      additionalProperties: false
      properties:
        assertion:
          description: The PublicKeyCredential navigator.credentials.get returned, serialized as JSON (PublicKeyCredential.toJSON()).
        passkeyToken:
          description: The passkeyToken /v1/login/passkey/begin answered.
          examples:
            - eyJhbGciOiJIUzI1NiJ9...
          minLength: 1
          type: string
      required:
        - passkeyToken
        - assertion
      type: object
    RefreshTokenInput:
      additionalProperties: false
      properties:
        refreshToken:
          description: The refresh token to exchange for a new access token.
          examples:
            - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
          type: string
        scope:
          description: Space-delimited scopes the application is requesting. Optional; the originally granted scope is reused when absent.
          examples:
            - openid profile email
          type: string
      required:
        - refreshToken
      type: object
    RequestAccessTokenInput:
      additionalProperties: false
      properties:
        clientId:
          examples:
            - 00000000-0000-0000-0000-000000000000
          type: string
        clientSecret:
          examples:
            - 00000000-0000-0000-0000-000000000000
          type: string
        code:
          examples:
            - 4%2F0AbCd...idp
          type: string
        codeVerifier:
          examples:
            - dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
          type: string
        grantType:
          enum:
            - password
            - client_credentials
            - sso_code
          examples:
            - password
          type: string
        password:
          examples:
            - password
          type: string
        state:
          examples:
            - kQ7f...opaque
          type: string
        username:
          examples:
            - johndoe
          type: string
      required:
        - grantType
      type: object
    SSODiscoveryInput:
      additionalProperties: false
      properties:
        email:
          examples:
            - user@acme.com
          type: string
      required:
        - email
      type: object
    SSODiscoveryResponse:
      additionalProperties: false
      properties:
        passkeyEnabled:
          type: boolean
        passwordEnabled:
          type: boolean
        provider:
          $ref: "#/components/schemas/SSOProviderListItem"
      required:
        - passwordEnabled
        - passkeyEnabled
      type: object
    SSOProviderListItem:
      additionalProperties: false
      properties:
        displayName:
          type: string
        id:
          type: string
        type:
          type: string
      required:
        - id
        - displayName
        - type
      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
    UserInfo:
      additionalProperties: false
      properties:
        email:
          description: Email address.
          examples:
            - john@example.com
          type: string
        emailVerified:
          description: Whether the email address has been verified.
          examples:
            - true
          type: boolean
        name:
          description: Full display name.
          examples:
            - John Doe
          type: string
        picture:
          description: URL of the user's profile picture.
          examples:
            - https://example.com/picture.jpg
          type: string
        preferredUsername:
          description: Preferred username.
          examples:
            - johndoe
          type: string
        profile:
          description: URL of the user's profile page.
          examples:
            - https://example.com/profile
          type: string
        sub:
          description: Subject identifier (the user's stable id).
          examples:
            - 00000000-0000-0000-0000-000000000000
          type: string
        tenantId:
          description: Tenant (organization) identifier the user belongs to.
          examples:
            - 00000000-0000-0000-0000-000000000000
          type: string
        tenantSlug:
          description: Human-readable tenant slug.
          examples:
            - banco-acme
          type: string
      required:
        - sub
        - name
        - preferredUsername
        - email
        - emailVerified
      type: object
  securitySchemes:
    BearerAuth:
      bearerFormat: JWT
      description: JWT bearer token issued by the identity provider.
      scheme: bearer
      type: http
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
openapi: 3.1.0
paths:
  /v1/authorize:
    post:
      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: []
      summary: Enforce a user permission
      tags:
        - User Permission
      x-mint:
        href: /pt/reference/platform/access-manager/validate-user-permission
  /v1/login/mfa/challenge:
    post:
      description: "Use this endpoint with `mfaType: email` to request a new verification code sent via email. The API also accepts `app`, but it does not send a code for that method: authenticator apps generate passcodes locally. Clients using an authenticator app can proceed directly to verification.\n\nRequires a valid `mfaToken` obtained from the access token endpoint."
      operationId: initiateMFAChallenge
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MFAChallengeInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MFAChallengeInitiatedResponse"
          description: The challenge request succeeded. For email, a verification code was sent. For app, no code is sent.
        "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
      summary: Initiate an MFA challenge
      tags:
        - MFA
      x-mint:
        href: /pt/reference/platform/access-manager/initiate-mfa-challenge
  /v1/login/mfa/confirm:
    post:
      description: "Confirms the factor started by setup with its first passcode, enables it, and continues the login with the normal MFA challenge under the SAME mfaToken. Wrong passcodes are charged to the same per-user attempt budget as verify (AUT-0018 at the cap). Public: authenticated by the enrollment-only mfaToken."
      operationId: confirmMFAEnrollment
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MFAConfirmInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MFAChallengeResponse"
          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
      summary: Confirm an MFA enrollment and continue the login
      tags:
        - MFA
      x-mint:
        href: /pt/reference/platform/access-manager/confirm-an-mfa-enrollment-and-continue-the-login
  /v1/login/mfa/setup:
    post:
      description: "Starts the enrollment of the factor an organization requires, for a login refused with 401 AUT-0019. Public: authenticated by the enrollment-only mfaToken of that refusal. For an authenticator app the answer carries the secret and the otpauth URL; for an email the code is sent to the account's own address. The recovery code is shown once. The server keeps the secret, so confirm sends only the passcode. A challenge token is not an enrollment token (AUT-0017)."
      operationId: setupMFAEnrollment
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MFASetupInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MFASetupResponse"
          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
      summary: Start enrolling a required MFA factor
      tags:
        - MFA
      x-mint:
        href: /pt/reference/platform/access-manager/start-enrolling-a-required-mfa-factor
  /v1/login/mfa/verify:
    post:
      description: "Verifies a one-time passcode or recovery code against the MFA session token and issues OAuth2 tokens. Public: authenticated by the mfaToken in the body. When the code is right but the organization requires a factor the person has not enrolled, no token is issued: the answer is 401 AUT-0019 with the same mfaToken (now enrollment-only) and the availableMethods to enroll, and the login continues through POST /v1/login/mfa/setup and /confirm."
      operationId: verifyMFAChallenge
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MFAVerifyInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Token"
          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
      summary: Verify an MFA challenge
      tags:
        - MFA
      x-mint:
        href: /pt/reference/platform/access-manager/verify-mfa-login
  /v1/login/oauth/access_token:
    post:
      description: |-
        Issues an OAuth2 access token. No Bearer token is needed; the grant itself is the credential.

        Two request formats are accepted, chosen by Content-Type, and each has its own response shape:
        - application/json with camelCase members (grantType, clientId, clientSecret, username, password, code, state, codeVerifier) answers with the camelCase token (accessToken, tokenType, expiresIn, ...).
        - application/x-www-form-urlencoded with the standard OAuth2 members (grant_type, client_id, client_secret, username, password, code) answers with the standard snake_case token (access_token, token_type, expires_in, ...). Client credentials may instead be sent as HTTP Basic authentication, which then takes precedence over client_id/client_secret in the form.

        grantType is one of password, client_credentials or sso_code. password requires username and password; client_credentials requires clientId and clientSecret; sso_code requires code, state and codeVerifier (the PKCE verifier of the code_challenge sent to GET /v1/sso/start), and is a JSON-only grant.

        When the person signing in has MFA enabled, a password or sso_code grant does not issue a token: it answers 200 with mfaRequired=true and an mfaToken, which is then sent to POST /v1/login/mfa/verify to obtain the token.

        When the person has no MFA factor and the organization requires one, a password or sso_code grant is refused with 401 AUT-0019 carrying an enrollment-only mfaToken and the availableMethods to enroll: the client enrolls through POST /v1/login/mfa/setup and /confirm, which continue the login with the normal challenge.

        Errors use the {code, title, message} envelope, plus fields on body validation errors. 400: Content-Type missing or not one of the two formats, malformed form or Basic credentials (AUT-0009), a grant missing the members it needs (AUT-0014), an invalid or expired SSO code (AUT-0027). 401: wrong username or password (AUT-1002), wrong client credentials (AUT-1004), password grant for a person created through SSO with no password (AUT-1006), a person with MFA whose sign-in did not reach the second-factor step (AUT-0015), a person with no MFA factor whose organization requires one (AUT-0019, with mfaToken and availableMethods), suspended or expired partner (AUT-1009, AUT-1010). 403: caller IP outside the IP allowlist (AUT-0021), person not allowed to sign in (AUT-1008), password grant for a person who has a passkey while the organization offers passkey sign-in (AUT-1019; checked only after the password was verified). 429: account temporarily locked after repeated failures (AUT-1007). 503 AUT-0028: the sign-in needs a second factor and this server has no MFA signing secret configured.
      operationId: requestAccessToken
      parameters:
        - description: Optional HTTP Basic client authentication (Basic base64(client_id:client_secret)), read on form requests only. When present it takes precedence over client_id/client_secret in the form body.
          in: header
          name: Authorization
          schema:
            description: Optional HTTP Basic client authentication (Basic base64(client_id:client_secret)), read on form requests only. When present it takes precedence over client_id/client_secret in the form body.
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RequestAccessTokenInput"
          application/x-www-form-urlencoded:
            schema:
              $ref: "#/components/schemas/AccessTokenForm"
      responses:
        "200":
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/OAuth2Token"
                  - $ref: "#/components/schemas/OAuth2TokenStandardResponse"
                  - $ref: "#/components/schemas/MFAChallengeResponse"
          description: OK
        "400":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Bad Request
        "401":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Unauthorized
        "403":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Forbidden
        "429":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Too Many Requests
        "500":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Internal Server Error
        "503":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Service Unavailable
      summary: Request an access token
      tags:
        - OAuth
      x-mint:
        href: /pt/reference/platform/access-manager/request-access-token
  /v1/login/oauth/refresh_token:
    post:
      description: "Exchanges a valid refresh token for a new OAuth2 access token. Public: authenticated by the refresh token in the body."
      operationId: refreshAccessToken
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RefreshTokenInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Token"
          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
      summary: Exchange a refresh token for an access token
      tags:
        - OAuth
      x-mint:
        href: /pt/reference/platform/access-manager/refresh-token
  /v1/login/passkey/begin:
    post:
      description: |-
        Resolves the tenant of the e-mail and answers the WebAuthn request options for navigator.credentials.get, with a passkeyToken naming this attempt for 5 minutes.

        Failures:
        - `403 AUT-1016` — passkey sign-in is not enabled for the tenant of this e-mail.
        - `403 AUT-0021` — the caller's network is outside the tenant's IP allowlist.
        - `401 AUT-1017` — the sign-in could not be completed, whatever the reason. On begin, Caradhras refused to open the ceremony.
        - `429 AUT-1018` — too many sign-in attempts for this e-mail (finish only).
        - `503 AUT-0028` — the server has no MFA_SECRET, so passkey sign-in is unavailable. 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: beginPasskeyLogin
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PasskeyBeginInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PasskeyBeginResponse"
          description: OK
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Unauthorized
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Forbidden
        "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
      summary: Begin a passkey login
      tags:
        - Passkey
      x-mint:
        href: /pt/reference/platform/access-manager/begin-a-passkey-login
  /v1/login/passkey/finish:
    post:
      description: |-
        Relays the browser's assertion for the attempt the passkeyToken names and issues OAuth2 tokens, the same envelope as the password grant. The passkeyToken works once.

        Failures:
        - `403 AUT-1016` — passkey sign-in is not enabled for the tenant of this e-mail.
        - `403 AUT-0021` — the caller's network is outside the tenant's IP allowlist.
        - `401 AUT-1017` — the sign-in could not be completed, whatever the reason. On begin, Caradhras refused to open the ceremony.
        - `429 AUT-1018` — too many sign-in attempts for this e-mail (finish only).
        - `503 AUT-0028` — the server has no MFA_SECRET, so passkey sign-in is unavailable. 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: finishPasskeyLogin
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PasskeyFinishInput"
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Token"
          description: OK
        "401":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Unauthorized
        "403":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Forbidden
        "422":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Unprocessable Entity
        "429":
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Detail"
          description: Too Many Requests
        "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
      summary: Finish a passkey login
      tags:
        - Passkey
      x-mint:
        href: /pt/reference/platform/access-manager/finish-a-passkey-login
  /v1/logout:
    post:
      description: "Invalidates the session. The ID token is supplied via the id_token_hint form field or, as a fallback, the Authorization Bearer header; at least one is required. Returns 204 No Content. 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: logoutUser
      parameters:
        - description: Bearer ID/access token, used as a fallback when id_token_hint is not supplied in the form body.
          in: header
          name: Authorization
          schema:
            description: Bearer ID/access token, used as a fallback when id_token_hint is not supplied in the form body.
            type: string
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              properties:
                id_token_hint:
                  description: OIDC ID token identifying the session to invalidate. Optional; when omitted, the Authorization Bearer header is used as the fallback credential.
                  type: string
              type: object
      responses:
        "204":
          description: No Content
        "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
      summary: Log out
      tags:
        - OAuth
      x-mint:
        href: /pt/reference/platform/access-manager/end-user-session
  /v1/permissions:
    get:
      description: "Retrieves the permissions granted to the Bearer token subject, as a resource-to-actions map. 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: getUserPermissions
      parameters:
        - description: Bearer access token identifying the caller. The request is rejected with 401 (AUT-0006) when absent.
          in: header
          name: Authorization
          schema:
            description: Bearer access token identifying the caller. The request is rejected with 401 (AUT-0006) when absent.
            type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                additionalProperties:
                  items:
                    type: string
                  type:
                    - array
                    - "null"
                type: object
          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: []
      summary: List the caller's permissions
      tags:
        - User Permission
      x-mint:
        href: /pt/reference/platform/access-manager/retrieve-user-permissions
  /v1/sso/discover:
    post:
      description: |-
        Tells the login screen, from an email address alone, how that person can sign in: whether password login is enabled for their tenant and which SSO provider, if any, it offers. It is called before login, by an unauthenticated browser, so the login screen can skip a manual tenant field; it changes nothing.

        It fails open: an email that resolves to no tenant answers 200 with passwordEnabled=true and no provider. The resolved tenant is never returned; the email is what the browser carries forward to GET /v1/sso/start.

        Errors use the {code, title, message} envelope, plus fields on body validation errors. 400: Content-Type missing or not application/json (AUT-0009), email missing (AUT-0001) or not an email address (AUT-0009), an unexpected member (AUT-0003). 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: discoverSSO
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SSODiscoveryInput"
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SSODiscoveryResponse"
          description: OK
        "400":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Bad Request
        "500":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Internal Server Error
        "503":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Service Unavailable
      summary: Discover how an email signs in
      tags:
        - SSO
      x-mint:
        href: /pt/reference/platform/access-manager/discover-how-an-email-signs-in
  /v1/sso/start:
    get:
      description: |-
        Starts an SSO login. The Console's login screen sends the browser here — not an API client — after POST /v1/sso/discover offered an SSO provider for the email typed. The tenant is resolved from the email server-side and is never accepted from the caller. The flow is stored server-side under a single-use state, and the browser is redirected (302, Location) to the identity provider's authorize URL; no cookie is set. The identity provider then returns the browser to the Console with a code, which is redeemed with the sso_code grant of POST /v1/login/oauth/access_token, presenting the PKCE verifier of the code_challenge sent here.

        Errors use the {code, title, message} envelope and are not redirects. 400: email, provider or code_challenge missing, or a code_challenge that is not a well-formed S256 challenge (AUT-0022). 401: this server has no SSO callback configured (AUT-0026). 404: the provider named is not one the tenant offers (AUT-0024). 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: startSSO
      parameters:
        - description: Email address of the person signing in. The tenant is derived from it server-side; it is never accepted from the caller.
          explode: false
          in: query
          name: email
          schema:
            description: Email address of the person signing in. The tenant is derived from it server-side; it is never accepted from the caller.
            examples:
              - user@acme.com
            type: string
          required: true
        - description: Name of the SSO provider to sign in with, as returned in provider.id by POST /v1/sso/discover.
          explode: false
          in: query
          name: provider
          schema:
            description: Name of the SSO provider to sign in with, as returned in provider.id by POST /v1/sso/discover.
            examples:
              - acme-oidc
            type: string
          required: true
        - description: S256 PKCE challenge (base64url, 43 characters). The matching verifier must be presented on the sso_code grant of POST /v1/login/oauth/access_token.
          explode: false
          in: query
          name: code_challenge
          schema:
            description: S256 PKCE challenge (base64url, 43 characters). The matching verifier must be presented on the sso_code grant of POST /v1/login/oauth/access_token.
            examples:
              - OgkYf8C0dZA55KwBPshQ5lPH4Fk3NCPRUkpnrJL8fgs
            type: string
          required: true
      responses:
        "302":
          description: Found
          headers:
            Location:
              schema:
                description: Authorize URL of the upstream identity provider the browser is sent to.
                type: string
        "400":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Bad Request
        "401":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Unauthorized
        "404":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Not Found
        "500":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Internal Server Error
        "503":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HTTPError"
          description: Service Unavailable
      summary: Start an SSO login
      tags:
        - SSO
      x-mint:
        href: /pt/reference/platform/access-manager/start-an-sso-login
  /v1/userinfo:
    get:
      description: "Returns the OIDC-standard user profile for the Bearer token subject."
      operationId: getUserInfo
      parameters:
        - description: Bearer access token identifying the caller. The request is rejected with 401 (AUT-0006) when absent.
          in: header
          name: Authorization
          schema:
            description: Bearer access token identifying the caller. The request is rejected with 401 (AUT-0006) when absent.
            type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserInfo"
          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: []
      summary: Get OIDC user info
      tags:
        - User Permission
      x-mint:
        href: /pt/reference/platform/access-manager/retrieve-user-information
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
servers:
  - url: https://auth.sandbox.lerian.net
