Tvarka ATK API Auth API

The eID authentication ceremony (`/v1/auth/*`).

OpenAPI Specification

tvarka-atk-api-auth-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Tvarka Atk Auth API
  version: 1.3.0
  description: 'Operations tagged Auth across 2 of this provider''s published API definitions: tvarka-atk-api-auth-openapi.yaml, tvarka-atk-api-openapi-original.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://atk.tvarka.pro/v1
  description: 'Production. Sandbox runs on the same host - provider credentials issued with

    environment=sandbox get the identical API against test-card material and are never billed.

    '
security:
- basicAuth: []
tags:
- name: Auth
  description: The eID authentication ceremony (`/v1/auth/*`).
paths:
  /auth/requests:
    servers:
    - url: https://atk.tvarka.pro/v1
      description: 'Production. Sandbox runs on the same host - provider credentials issued with

        environment=sandbox get the identical API against test-card material and are never billed.

        '
    post:
      tags:
      - Auth
      operationId: createAuthRequest
      summary: Create an authentication request (server-to-server)
      description: 'Called by the provider''s backend with HTTP Basic (`keyId:keySecret`). `audience` must be an

        exact origin on the provider''s allow-list. Physical requests return a short-lived `clientToken`;

        NFC requests return a pairing hint; Smart-ID/Mobile-ID requests remain entirely server-side.

        '
      x-codeSamples:
      - lang: curl
        label: Smart-ID
        source: "curl -u \"$ATK_KEY_ID:$ATK_KEY_SECRET\" https://atk.tvarka.pro/v1/auth/requests \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"audience\":\"https://app.example\",\"method\":\"smart_id\",\"personalCode\":\"39001010000\"}'\n"
      - lang: curl
        label: Mobile-ID
        source: "curl -u \"$ATK_KEY_ID:$ATK_KEY_SECRET\" https://atk.tvarka.pro/v1/auth/requests \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"audience\":\"https://app.example\",\"method\":\"mobile_id\",\"personalCode\":\"39001010000\",\"phoneNumber\":\"+37061234567\"}'\n"
      security:
      - basicAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthRequestCreate'
            examples:
              physicalAtk:
                summary: Primary ATK desktop-reader method
                value:
                  audience: https://app.example
                  method: physical
              smartId:
                summary: Optional Smart-ID method
                value:
                  audience: https://app.example
                  method: smart_id
                  personalCode: '39001010000'
              mobileId:
                summary: Optional Mobile-ID method
                value:
                  audience: https://app.example
                  method: mobile_id
                  personalCode: '39001010000'
                  phoneNumber: '+37061234567'
      responses:
        '202':
          description: Request created; awaiting the ATK client or remote user authorization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthRequestCreated'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
  /auth/{requestId}/certificate:
    servers:
    - url: https://atk.tvarka.pro/v1
      description: 'Production. Sandbox runs on the same host - provider credentials issued with

        environment=sandbox get the identical API against test-card material and are never billed.

        '
    post:
      tags:
      - Auth
      operationId: submitAuthCertificate
      summary: Submit the card's authentication certificate; receive the DTBS + challenge
      description: 'Called by the client with `Authorization: Bearer <clientToken>`. The API validates the

        certificate (chain, revocation, purpose = authentication, key usage), builds the canonical

        challenge, and returns the exact `dtbs` the card must sign plus a single-use `operationToken`.

        Physical/NFC only; server-side methods do not call this endpoint.

        '
      security:
      - clientToken: []
      parameters:
      - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CertificateSubmit'
      responses:
        '200':
          description: DTBS + challenge + operation token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CertificateChallenge'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /auth/{requestId}/complete:
    servers:
    - url: https://atk.tvarka.pro/v1
      description: 'Production. Sandbox runs on the same host - provider credentials issued with

        environment=sandbox get the identical API against test-card material and are never billed.

        '
    post:
      tags:
      - Auth
      operationId: completeAuth
      summary: Submit the raw card signature; receive the verified identity
      description: 'Called by the client with `Authorization: Bearer <clientToken>` and the single-use

        `operationToken` in the body. The API verifies the signature against the stored `dtbs` and the

        certificate''s public key, enforces the identity-swap guard, and returns the verified identity

        (and the optional `assertion` JWT). Retry-safe: a repeat with the same tuple returns the same

        result; a different signature/cert after the token is claimed is rejected.

        Physical/NFC only; server-side methods complete asynchronously.

        '
      security:
      - clientToken: []
      parameters:
      - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompleteSubmit'
      responses:
        '200':
          description: Authenticated - verified identity.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthResult'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /auth/{requestId}:
    servers:
    - url: https://atk.tvarka.pro/v1
      description: 'Production. Sandbox runs on the same host - provider credentials issued with

        environment=sandbox get the identical API against test-card material and are never billed.

        '
    get:
      tags:
      - Auth
      operationId: getAuthRequest
      summary: Poll request status / fetch the result
      description: 'Readable with the provider''s Basic credentials for every method, or with the request''s

        `clientToken` for physical/NFC requests. Smart-ID/Mobile-ID providers poll this endpoint or

        consume the terminal webhook.

        '
      security:
      - basicAuth: []
      - clientToken: []
      parameters:
      - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: Current state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthRequestState'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /auth/{requestId}/cancel:
    servers:
    - url: https://atk.tvarka.pro/v1
      description: 'Production. Sandbox runs on the same host - provider credentials issued with

        environment=sandbox get the identical API against test-card material and are never billed.

        '
    post:
      tags:
      - Auth
      operationId: cancelAuthRequest
      summary: Cancel a non-terminal request
      security:
      - basicAuth: []
      - clientToken: []
      parameters:
      - $ref: '#/components/parameters/RequestId'
      responses:
        '200':
          description: Cancelled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthRequestState'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  schemas:
    CertificateSubmit:
      type: object
      required:
      - certificate
      properties:
        certificate:
          type: string
          format: byte
          description: Base64 DER of the card's **authentication** certificate.
    ErrorBody:
      type: object
      required:
      - code
      - message
      properties:
        code:
          $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
        requestId:
          type: string
          format: uuid
        retryable:
          type: boolean
    Method:
      type: string
      enum:
      - physical
      - nfc
      - smart_id
      - mobile_id
      example: physical
      description: physical = desktop reader; nfc = phone tap; smart_id/mobile_id = server-side remote eID.
    AuthResult:
      type: object
      required:
      - status
      - method
      - sig
      - cert
      properties:
        status:
          type: string
          const: done
        method:
          $ref: '#/components/schemas/Method'
        sig:
          type: string
          format: byte
          description: 'The raw card signature over the audience-bound challenge, returned so the relying party can

            verify identity independently of `assertion`. Audience-binding prevents cross-RP relay.

            '
        cert:
          type: object
          properties:
            subject:
              $ref: '#/components/schemas/CertSubject'
            der:
              type: string
              format: byte
        assertion:
          type: string
          description: 'Optional short-lived Tvarka-signed JWT (ES256), verifiable against the JWKS endpoint. Claims:

            iss=atk.tvarka.pro, sub=<personal code>, aud=<audience>, iat, exp, jti, request_id

            (binds the assertion to this ceremony), given_name, family_name, cert_fp,

            authentication_method, amr. NOT OIDC.

            Optional by contract - integrators may ignore it and verify the raw `sig` themselves.

            '
    Error:
      type: object
      required:
      - error
      properties:
        error:
          $ref: '#/components/schemas/ErrorBody'
    SignatureAlgorithm:
      type: string
      description: Card-reported JWS-style algorithm.
      enum:
      - ES256
      - ES384
    AuthRequestCreated:
      type: object
      required:
      - requestId
      - method
      - verificationCode
      - status
      - expiresAt
      description: Physical requests return `clientToken`; NFC requests return `pairing`; remote methods return neither.
      properties:
        requestId:
          type: string
          format: uuid
        method:
          $ref: '#/components/schemas/Method'
        verificationCode:
          type: string
          description: NFC anti-relay code, or the user verification code for Smart-ID/Mobile-ID.
        clientToken:
          type: string
          description: Scoped bearer JWT for physical-card `/certificate` + `/complete`; absent for remote methods.
        status:
          $ref: '#/components/schemas/Status'
        expiresAt:
          type: string
          format: date-time
        challengeProfile:
          type: string
          const: atk-auth-v1
        nonce:
          type: string
          description: 'Server-minted challenge nonce (see `Challenge`), so the provider backend can

            re-derive `dtbs` and verify `sig` independently - no device relay needed.

            '
        pairing:
          allOf:
          - $ref: '#/components/schemas/PairingHint'
          description: Present only when method == nfc.
    AuthRequestState:
      type: object
      required:
      - requestId
      - method
      - status
      properties:
        requestId:
          type: string
          format: uuid
        method:
          $ref: '#/components/schemas/Method'
        status:
          $ref: '#/components/schemas/Status'
        verificationCode:
          type: string
          description: Present while a Smart-ID/Mobile-ID request is non-terminal.
        nonce:
          type: string
          description: Server-minted challenge nonce (see `Challenge`) - enables independent `sig` verification from polling alone.
        cert:
          type: object
          properties:
            subject:
              $ref: '#/components/schemas/CertSubject'
            der:
              type: string
              format: byte
              description: Base64 DER, present once status == done.
        sig:
          type: string
          format: byte
        assertion:
          type: string
        error:
          $ref: '#/components/schemas/ErrorBody'
    ErrorCode:
      type: string
      description: 'The full stable error-code catalog of the ATK API family (auth + sign + services);

        each endpoint returns the subset that applies to it. By HTTP status:

        400 invalid_json, missing_field, invalid_field, invalid_webhook_url, invalid_document_ref.

        401 invalid_basic_credentials, invalid_client_token, client_token_expired,

        operation_token_expired, invalid_download_token.

        403 origin_not_allowed, ip_not_allowed, format_not_allowed, document_ref_host_not_allowed,

        method_not_allowed, tenant_suspended, tier_forbidden.

        404 request_not_found, pairing_not_found, document_not_ready.

        409 request_terminal, operation_token_spent, identity_swap, idempotency_conflict,

        service_in_progress, pairing_not_available, pairing_already_claimed.

        410 pairing_expired. 413 document_too_large.

        422 cert_invalid, untrusted_chain, cert_revoked, cert_expired, not_qualified,

        cert_purpose_mismatch, signature_invalid, document_hash_mismatch, document_size_mismatch.

        429 rate_limited. 500 assembly_failed. 502 document_ref_fetch_failed.

        503 erasure_failed, pairing_service_unavailable, service_unavailable.

        The catalog can grow in minor versions - fall back to HTTP status semantics

        for codes you do not recognize.

        '
      enum:
      - invalid_json
      - missing_field
      - invalid_field
      - invalid_webhook_url
      - invalid_document_ref
      - invalid_basic_credentials
      - invalid_client_token
      - client_token_expired
      - operation_token_expired
      - invalid_download_token
      - origin_not_allowed
      - ip_not_allowed
      - format_not_allowed
      - document_ref_host_not_allowed
      - method_not_allowed
      - tenant_suspended
      - tier_forbidden
      - request_not_found
      - pairing_not_found
      - document_not_ready
      - request_terminal
      - operation_token_spent
      - identity_swap
      - idempotency_conflict
      - service_in_progress
      - pairing_not_available
      - pairing_already_claimed
      - pairing_expired
      - document_too_large
      - cert_invalid
      - untrusted_chain
      - cert_revoked
      - cert_expired
      - not_qualified
      - cert_purpose_mismatch
      - signature_invalid
      - document_hash_mismatch
      - document_size_mismatch
      - rate_limited
      - assembly_failed
      - document_ref_fetch_failed
      - erasure_failed
      - pairing_service_unavailable
      - service_unavailable
    PairingHint:
      type: object
      properties:
        pairingUrl:
          type: string
          format: uri
          example: https://sign.tvarka.pro/atk-login/#PAIRING_TOKEN
        deepLink:
          type: string
          example: tvarkasign://atk/pair/PAIRING_TOKEN
        qrPayload:
          type: string
          example: https://sign.tvarka.pro/atk-login/#PAIRING_TOKEN
    HashAlgOid:
      type: string
      description: Digest algorithm OID, curve-matched. SHA-256 = 2.16.840.1.101.3.4.2.1; SHA-384 = 2.16.840.1.101.3.4.2.2.
      enum:
      - 2.16.840.1.101.3.4.2.1
      - 2.16.840.1.101.3.4.2.2
    AuthRequestCreate:
      type: object
      required:
      - audience
      - method
      additionalProperties: false
      oneOf:
      - title: Physical ATK
        properties:
          method:
            const: physical
        not:
          anyOf:
          - required:
            - personalCode
            properties:
              personalCode: {}
          - required:
            - phoneNumber
            properties:
              phoneNumber: {}
      - title: ATK over NFC
        properties:
          method:
            const: nfc
        not:
          anyOf:
          - required:
            - personalCode
            properties:
              personalCode: {}
          - required:
            - phoneNumber
            properties:
              phoneNumber: {}
      - title: Smart-ID
        required:
        - personalCode
        properties:
          method:
            const: smart_id
        not:
          required:
          - phoneNumber
          properties:
            phoneNumber: {}
      - title: Mobile-ID
        required:
        - personalCode
        - phoneNumber
        properties:
          method:
            const: mobile_id
      properties:
        audience:
          type: string
          description: The relying-party origin (must be exactly on the provider's allow-list), e.g. https://www.epaslaugos.lt.
          example: https://www.epaslaugos.lt
        method:
          $ref: '#/components/schemas/Method'
        personalCode:
          type: string
          pattern: ^[0-9]{11}$
          example: '39001010000'
          description: Required for Smart-ID and Mobile-ID; rejected for physical/NFC.
        phoneNumber:
          type: string
          pattern: ^\+3706[0-9]{7}$
          example: '+37061234567'
          description: Required for Mobile-ID, rejected for every other method.
        message:
          type: string
          description: Optional short message the client may display to the user.
        externalId:
          type: string
          description: Provider's own correlation id (echoed back, deduped).
        webhookUrl:
          type: string
          format: uri
          description: Optional public HTTPS webhook for the terminal status; private/non-global destinations are rejected.
    CompleteSubmit:
      type: object
      required:
      - signature
      - signatureAlgorithm
      - operationToken
      properties:
        signature:
          type: string
          format: byte
          description: Base64 raw card signature over `dtbs` (auth key).
        signatureAlgorithm:
          $ref: '#/components/schemas/SignatureAlgorithm'
        signatureEncoding:
          $ref: '#/components/schemas/SignatureEncoding'
        operationToken:
          type: string
    CertSubject:
      type: object
      description: Selected subject fields from the certificate. `serialNumber` holds `PNOLT-<personal code>`.
      properties:
        serialNumber:
          type: string
          example: PNOLT-39001010000
        givenName:
          type: string
        sn:
          type: string
          description: Surname.
        cn:
          type: string
        c:
          type: string
          example: LT
    CertificateChallenge:
      type: object
      required:
      - requestId
      - dtbs
      - dtbsHashAlgOid
      - operationToken
      - challenge
      - cert
      properties:
        requestId:
          type: string
          format: uuid
        dtbs:
          type: string
          format: byte
          description: 'Base64 of the exact digest the card must sign (ECDSA prehashed). Built as the `atk-auth-v1`

            construction - see `Challenge`.

            '
        dtbsHashAlgOid:
          $ref: '#/components/schemas/HashAlgOid'
        operationToken:
          type: string
          description: Single-use JWT bound to {tenant, requestId, purpose, certFp, dtbsHash}; the nonce is bound indirectly via dtbs. Returned at /complete.
        verificationCode:
          type: string
        challenge:
          $ref: '#/components/schemas/Challenge'
        cert:
          type: object
          required:
          - subject
          description: 'Echoes only the parsed `subject` (the client itself just submitted the DER).

            The certificate DER is returned at `/complete` and on GET once done.

            '
          properties:
            subject:
              $ref: '#/components/schemas/CertSubject'
    Status:
      type: string
      description: 'Flat request status. Non-terminal - `pending`, `awaitingCard`, `awaitingCredentials`,

        `finalizing`. Terminal success - `done`. Terminal failure -

        `cancelled`/`timeout`/`deviceError`/`pinBlocked`/`cardRemoved`/`certInvalid`.

        `awaitingCredentials` is SDK-reported (CAN/PIN entry is out-of-band).

        '
      enum:
      - pending
      - awaitingCard
      - awaitingCredentials
      - finalizing
      - done
      - cancelled
      - timeout
      - deviceError
      - pinBlocked
      - cardRemoved
      - certInvalid
    SignatureEncoding:
      type: string
      enum:
      - P1363
      - DER
      default: P1363
      description: Raw ECDSA signature encoding. P1363 = fixed-width r||s; DER = SEQUENCE(r, s). Informational - the server auto-detects and accepts either encoding regardless of this field.
    Challenge:
      type: object
      description: 'Canonical `atk-auth-v1` anti-relay challenge. The server issues `nonce`; `dtbs` returned above =

        `HASH( HASH(utf8(audience_origin)) || HASH(utf8(nonce)) )` with `HASH` matched to the auth-key

        curve (P-256 -> SHA-256, P-384 -> SHA-384). Versioned - future profiles never reinterpret an

        existing `dtbs`. This binding is what a relying party (e.g. ePaslaugos) audits.

        '
      required:
      - profile
      - audience
      - nonce
      properties:
        profile:
          type: string
          const: atk-auth-v1
        audience:
          type: string
        nonce:
          type: string
          description: Server-issued base64url challenge string (44-128 chars).
  responses:
    Conflict:
      description: State/idempotency conflict (spent operation token, identity swap, terminal request).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Unknown request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Authorized but not permitted (origin/format/tenant).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Too many requests.
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unprocessable:
      description: Semantic reject (cert purpose/chain/revocation, dtbs mismatch, bad signature).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequest:
      description: Malformed input.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing/invalid credentials or client token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: A required remote or erasure service is temporarily unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  parameters:
    RequestId:
      name: requestId
      in: path
      required: true
      description: The `requestId` returned by `POST /auth/requests`.
      schema:
        type: string
        format: uuid
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: 'Provider server-to-server credentials `keyId:keySecret`. Server-to-server only, also gated by the

        provider''s server IP allow-list. Never placed in a browser/mobile client.

        '
    clientToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Short-lived, per-request JWT (`ES256`) minted at request creation, scoped

        `{tenant, requestId, purpose, method, allowedOrigins}`. Safe to hand to a browser/mobile client:

        it cannot create requests, read tenant data, or touch other requests. For browser clients the API

        enforces `Origin` against `allowedOrigins` (rejects cross-origin replay).

        '
    downloadToken:
      type: apiKey
      in: query
      name: downloadToken
      description: One-off token returned with a completed sign result, for fetching the signed document.
externalDocs:
  description: Quickstart, SDKs, test data, pricing and lifecycle policy
  url: https://atk.tvarka.pro/docs/
x-refined-from:
- tvarka-atk-api-auth-openapi.yaml
- tvarka-atk-api-openapi-original.json