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 `. 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 ` 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=, aud=, 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-`. 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