Formality · Authentication Profile

Formality Authentication

Authentication

Formality secures its APIs with http across 2 declared security schemes, as derived from its OpenAPI definitions.

CompanyAi MlLegalContract ManagementDocument-ManagementAsset IntelligenceComplianceSoftware-as-a-Service
Methods: http Schemes: 2 OAuth flows: API key in:

Security Schemes

refreshToken http
scheme: bearer · in: header ()
accessToken http
scheme: bearer · in: header ()

Source

Authentication Profile

formality-authentication.yml Raw ↑
generated: '2026-08-17'
method: searched
source: https://help.formality.com/integrations/api
docs: https://help.formality.com/integrations/api
note: >-
  Derived by hand from the help centre, not from an OpenAPI document. Formality
  publishes a Swagger UI at https://app.eu1.formality.com/-/api-doc-swagger but it
  HTTP 302s to https://auth.eu1.formality.com/?callbackUrl=..., and
  /api/v1/openapi.json and /api/v1/swagger.json both return 401, so no
  securitySchemes block could be read. Everything below is stated verbatim in
  Formality's own API documentation.
summary:
  types: [http]
  api_key_in: []
  oauth2_flows: []
  scheme: bearer
  token_exchange: true
  end_user_sso: [Google, Microsoft]
schemes:
- name: refreshToken
  type: http
  scheme: bearer
  role: credential
  in: header
  header: Authorization
  format: 'Authorization: Bearer <your-refresh-token>'
  issued_by: Personal Settings > Formality API > New Token
  lifetime: operator-chosen, "from a few days to a full year"
  revocable: true
  shown_once: true
  usage_visibility: >-
    The token list shows when and where each token was last used.
  sources: [https://help.formality.com/integrations/api]
  note: >-
    A long-lived PERSONAL refresh token. It is not used to call resource endpoints;
    its only documented purpose is to be exchanged at GET /api/v1/token for a
    short-lived access token. Because it is minted per user in Personal Settings, an
    integration inherits that individual's permissions — Formality documents no
    separate service-account or machine credential.
- name: accessToken
  type: http
  scheme: bearer
  role: access
  in: header
  header: Authorization
  format: 'Authorization: Bearer <your-access-token>'
  obtained_from: GET /api/v1/token
  lifetime_seconds: 300
  lifetime_note: >-
    "The access token has a lifespan of 5 minutes, once expired you'll need to
    generate a new one." No refresh-token rotation, expiry hint or Retry-After style
    signal is documented, so a client must either re-exchange before every call or
    handle a 401 and retry.
  response_shape: '{"token": "<access token>"}'
  sources: [https://help.formality.com/integrations/api]
flow:
  style: two-step bearer exchange
  steps:
  - step: 1
    action: Create a personal Refresh Token in Personal Settings > Formality API
    note: The full token is displayed only once at creation.
  - step: 2
    action: 'GET /api/v1/token with header: Authorization: Bearer <refresh-token>'
    returns: 'JSON body {"token": "..."} containing the 5-minute access token'
  - step: 3
    action: 'Call resource endpoints with Authorization: Bearer <access-token>'
scoping:
  model: workspace-path
  note: >-
    Authorization is scoped by the workspaceId path segment rather than by token
    scopes. The workspaceId is the slug that follows the application host in the app
    URL (app URL .../myCompany/agreements => workspaceId "myCompany"), and it is a
    required segment of every resource path. There is no OAuth authorization server,
    no scope vocabulary and no consent screen, which is why scopes/ was deliberately
    not written for this provider.
end_user_authentication:
  sso: [Microsoft, Google]
  magic_link: true
  enforce_sso_toggle: true
  enforce_sso_note: >-
    An "Imposer la connexion SSO" toggle in workspace Security settings blocks
    magic-link sign-in and terminates existing non-SSO sessions, forcing
    re-authentication through Google or Microsoft.
  allowed_email_domains: true
  source: https://help.formality.com/setup-permissions/user-management
  note: >-
    This is human sign-in to the application, NOT API authentication. It is recorded
    because the Swagger UI is gated behind it.
observed_behaviour:
- url: https://app.eu1.formality.com/api/v1/token
  status: 401
  fetched: '2026-08-17'
- url: https://app.eu1.formality.com/api/v1/demo/agreements
  status: 401
  fetched: '2026-08-17'
- url: https://app.eu1.formality.com/api/v1/openapi.json
  status: 401
  fetched: '2026-08-17'
- url: https://app.eu1.formality.com/-/api-doc-swagger
  status: 302
  location: https://auth.eu1.formality.com?callbackUrl=https://app.eu1.formality.com/-/api-doc-swagger
  fetched: '2026-08-17'
caveat: >-
  The 401 responses above are a BLANKET gate, not endpoint confirmation: a
  deliberately nonsensical path
  (/api/v1/nonexistentgarbagexyz/zzznotreal) also returns 401 with the same 17-byte
  "401 Unauthorized" body. Unauthenticated probing therefore proves the /api/v1/
  surface is live and auth-gated, but it cannot confirm which individual endpoints
  exist. Every endpoint recorded in this repo comes from Formality's published
  documentation, not from probe inference.
gaps:
- No OpenAPI/Swagger document is reachable without a session.
- No /.well-known/openid-configuration or oauth-authorization-server is served.
- No documented token-rotation, key-prefix or sandbox-vs-live credential separation.
- No documented rate limit or 429 behaviour on the token-exchange endpoint.