Skip to content
This page is also available in: Čeština, Українська, Slovensky

Security - technical detail

Updated: September 20, 2026

Technical companion to How we protect your data. This describes selected application mechanisms; it is not an infrastructure certification or a promise that all data categories receive identical treatment.

I. Identity data - Bank iD and manual verification

Identity is verified through Bank iD or by manual verification by an authorized staff member on an online call. We store verification results and necessary identity details; selected sensitive fields are encrypted at application level.

Bank iD. The app processes verified data from the authorization flow and retains an identity snapshot for employment and payroll purposes. It does not receive bank sign-in credentials.

Manual verification. An authorized staff member records the details from the document on an online call; no image of the document is uploaded to production storage. The result carries the source MANUAL_ADMIN and the same audit trail as Bank iD.

Audit and retention. Identity and signing events have audit records. Operational copies, verification materials and statutory employment records have different retention purposes; a single blanket 60-day period does not apply. Account erasure does not remove all statutory records.

II. Tokens and sessions

On sign-in, the client receives two tokens: a short-lived JWT access token and a re-usable refresh token (14 days sliding, 365 days absolute).

The refresh token is opaque. A 64-character hex random string - not a JWT. It can't be "decoded" outside our backend. It rotates on every use: the old token is immediately marked consumed, and a new one is issued.

Rotation and retries. RefreshTokenService uses family_id for a single session chain. Refreshing marks the previous token as consumed. A bounded 300-second recovery window permits retries when the successor is unused; its recovery cache temporarily contains the replacement token. Reuse outside the permitted conditions revokes that family, not every independent user session.

Active devices. At /account/security/sessions (web) and /sessions (mobile), users see all active sessions, last activity, and the device / location (derived from the User-Agent and the IP address stored with every issued session token; IP addresses from earlier refreshes remain in the token audit chain until the account is deleted, and IP addresses of signing and verification actions remain in the audit records). Sessions can be revoked individually or in bulk; revocation invalidates the family, not just a single token.

III. Files and documents

Production storage has two parts: public images and chat and support attachments are stored in Amazon S3 (eu-central-1, Frankfurt) and public images are delivered through Amazon CloudFront; contracts, signed documents (DPP, declarations), BOZP certificates, certifications and CVs are stored in Hetzner Object Storage (Falkenstein, Germany). Development environments can use MinIO. Public images and private documents have different access requirements.

File links. For managed objects, the app uses an object key and issues URLs according to purpose and permissions. Signed links expire; anyone holding a valid link can download the file while it is valid. Signed links to private documents are typically valid for 60 seconds, chat and support attachments for up to 72 hours. This does not prevent copying.

Three-tier access control (apps/api/src/modules/storage/storage.controller.ts):

  1. Public files (company logos, profile photos, listing photos) - available without authorization at a permanent address through a CDN with long-term caching; they are not signed and are intended for publication.
  2. Authenticated assets (contracts, job documents) - JWT validation + ownership check before issuing a signed URL.
  3. Tenant-scoped assets (internal company documents) - additionally checks the X-Active-Company-Id header, so an admin of company A cannot access company B's files.

IV. Encryption in transit and of selected data at rest

In transit. Public interfaces use HTTPS/TLS. Specific TLS and proxy settings belong to the configuration of each deployment.

At rest. The app uses AES-256-GCM for selected sensitive identity and payroll data. This does not guarantee encryption of the entire database disk, every file or every backup.

Cross-tenant scope safety. Public reads on the companies table go through excludePlatformCompany() (apps/api/src/common/scopes/exclude-platform-company.scope.ts) so the internal FIXIT_PLATFORM shell employer cannot leak into customer-facing listings, search, or Elasticsearch indexing.

User input. Protection includes validation, permission checks, safe rendering and URL checks before server-side fetching. Different content types have different processing; not every input passes through identical sanitization.

V. GDPR and contacts

FixIt.app s.r.o. is the data controller under Article 4 GDPR. Our Privacy Policy covers the legal framework and your rights.

Security reports: security@fixit.app. Include reproduction steps and impact; please coordinate publication with us.


Questions about these mechanisms: security@fixit.app.