Skip to content

Signing Platform Core API

By Romi Fadli, S.Kom. 9 min read Security & Secrets
On this page
A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

Signing Platform Core API is the heart of a document-signing platform: the Laravel application that owns the people, the organisations, the client systems, and the records, and that orchestrates every specialised service around it. It does far more than sign. It manages user accounts and their identities, organisations and their units, the external systems that sign through the platform, documents with their signers and their history, signature stamps, and the certificates people sign with — and it hands the heavy work of signing, rendering, timestamping, and storing to services built for it.

It is the one module in the platform that belongs to a single project: it holds that project's rules and data, while the services it calls are reusable anywhere. I still build and describe it as a module, so the platform stays one consistent set of parts with one core at the centre.

At a glance

Language & frameworkPHP, with Laravel, on PostgreSQL and Redis
ArchitectureStateless Laravel Core
Version2.15.1
StatusStable, in production
FormAn HTTP API with background workers, plus a server-rendered public home page; the main user interface is a separate single-page application
Source codePrivate
What the module is and where it stands.

What it does

A. Runs the signing of documents

A document is uploaded, given one or more signers in ordered stages, and signed by each in turn. Every signature is a background job: the request is accepted at once, the document is marked as being signed, and the signer service does the cryptographic work with the signer's own certificate. The signed file's hash is recorded, so a document can be found again by its content, and each new signed version is chained to the one before it.

B. Manages people and their identities

Accounts can be created directly or through external identity providers, protected by two-factor authentication, and managed across devices. Before someone can hold a signing certificate, their identity is verified: personal data, an identity document, and a live face challenge, checked by a human reviewer.

C. Issues and watches certificates

The core requests certificates from the signing certificate authority on a person's behalf, keeps at most one active certificate per person in each organisation, and checks revocation live against the authority, updating its own records when the authority's answer differs.

D. Organises who may do what

Organisations contain units, units contain members, and roles are ranked so nobody can act on a peer or on someone above them. Organisations can admit members automatically from an allowlist of e-mail addresses, and administrators can suspend accounts without deleting them.

E. Lets other systems sign through it

Client systems — the platform's software-as-a-service customers — call a separate client API with their own secrets, allowed origins, and permissions granted per operation. Trusted internal clients can bind users directly; external clients need the user's consent. Results are delivered back to each client through webhooks, sent in the background and recorded until they succeed.

F. Shows the platform to the public

The public home page is rendered by the core itself, with content that administrators can update, so search engines can index it; the application people work in lives in its own repository.

Interface

AreaWhat it exposes
Authenticationlogin, rotating refresh tokens, two-factor, external identity providers, the public signing keys of its tokens
Usersaccounts, devices, roles, stamp templates
Organisationsorganisations, units, members, e-mail allowlists
Identityidentity verification, face challenges, reviewer queues
Certificatesrequests, approvals, revocations, live status
Documents and filesuploads through short-lived links, signers, signing, signed versions
Client systemsclient management, and a separate client API with its own authentication
Administrationdashboard, failed jobs, public page content
Readinessone endpoint that checks the database, the cache, storage, and every service the core depends on
The areas of the API, each in its own route file.

Standards

StandardWhat it guarantees here
JSON Web Tokens with RS256, and a published JWKSone token format for every login, verifiable by any service without calling the core
OAuth 2.0 and OpenID Connect, with PKCEsign-in through external providers, exchanged for the core's own token
TOTP (RFC 6238)two-factor authentication with any authenticator app
OCSP (RFC 6960)live revocation status for every certificate the platform uses
Presigned URLs, AWS Signature Version 4files moved between browsers and storage without passing through the core
W3C Trace Context and OpenTelemetryone trace from the user's request through every service and background job
UUIDv7public identifiers and request ids that sort by time and reveal no internal sequence
The standards the core follows, and what each one guarantees.

Inside

The core follows Stateless Laravel Core: nodes hold nothing, slow work runs as queued jobs, files never touch the server, every login ends in the core's own token, and every request, job, and outgoing call is traced. Each specialised service is reached through one class of its own, with its own configuration, timeout, and family of errors.

Design decisions

The core decides; specialised services do the work. Signing, timestamping, issuing certificates, rendering thumbnails, challenging faces, storing files, and looking up regions each belong to a service built for that job, and the core orchestrates them. When a service lacks something the core needs, I ask for it in that service rather than work around it here — the batch endpoint the storage service now offers exists because the core needed it. Regional data used to live in the core's own tables; it moved to the address service, and organisations now keep a snapshot of their region instead of a foreign key, so a change in official region codes can never silently break an existing record.

Signing never makes anyone wait. A signing request is checked before it is queued — the signer's passphrase is verified, so a job never starts from a wrong one — then accepted at once, with the document marked as being signed rather than signed. The passphrase travels encrypted through the queue. A failed webhook to a client never undoes a signature; the delivery is retried and recorded separately.

Personal data is protected as data, not only as traffic. Phone numbers, birth details, identity numbers, and two-factor secrets are encrypted in the database, and identity numbers can be looked up without decrypting anything. The plain identity number never appears in a login response, where it would end up in browser storage and logs. One registry is the only place that decides whether an identity number is already taken, so no two code paths can disagree. Identity photos shown to reviewers carry a watermark identifying the viewer, so a leaked image can be traced, and face images are deleted from storage once a verification is approved.

Nothing reveals what exists. Public identifiers are random UUIDs, never the internal sequence, so records cannot be enumerated by counting. Endpoints that could reveal whether an account exists — password resets, verification e-mails — answer the same way either way. Actions with lasting impact require the password again, and administrators cannot act on peers or on roles above their own.

Every signed version stays connected. The hash of each signed file is stored, so a document can be identified from the file alone. When a signed document is uploaded again for further signatures, its new version is chained to the previous hash, and because file bytes never pass through the core, that hash is read back from storage, not computed from an upload the core never saw.

Two kinds of client, two levels of trust. Internal clients — systems run by the same organisation — are trusted to bind their users directly and receive default permissions. External clients must obtain each user's consent through a one-time token and are limited to the operations they were granted, checked on every call. Client secrets are stored hashed, and the user a client refers to is identified by a reference the platform derives itself rather than an identifier the client invented.

Certificates are checked where they live. Revocation is asked of the certificate authority live, and when its answer differs from the core's records, the records follow the authority, with the real revocation reason kept. The authority's own certificates are fetched once and cached rather than stored as files on the server.

Storage is accounted for. Every object key the database refers to is known to one index, and nothing is deleted from storage without asking it first, and a read-only audit compares storage with the database before anything is swept.

Specifications

InputsRequests from the web application, from client systems, and from administrators
OutputsJSON responses, signed documents in storage, certificates on behalf of users, webhooks to client systems, e-mail
Depends onPostgreSQL, Redis, and the platform's services for storage, addresses, certificates, timestamps, signing, thumbnails, and face challenges
Background workQueued jobs for signing, thumbnails, webhooks, e-mail, and allowlist processing
SecurityRS256 tokens with rotating refresh tokens, two-factor authentication, rate limits in Redis, encrypted personal data, ranked roles
ObservabilityOpenTelemetry traces, logs, metrics, and audit events, continued across every service and job
Runs asA container with the web server and queue workers under one supervisor, scaled by adding copies
What the core takes, returns, and needs.

The storage service through which every file, stamp, and signed document travels.

The address service that supplies regions for organisations.

The certificate authority that issues each signer's certificate and answers revocation checks.

The timestamp authority behind every signature's date.

The root publisher at the top of the platform's chain of trust.

The signer that turns each queued request into a long-term PDF signature.

The renderer that gives every document its first-page thumbnail.

The face challenge that proves a person was present during identity verification.

Where the trace of a request through all these services ends up.

Terms

Orchestration
Coordinating several services so that together they complete one piece of work, without doing that work itself.
Enumeration
Discovering which records or accounts exist by trying identifiers one after another and comparing the answers.
Webhook
A request a system sends to another system's address to tell it that something has happened.
Software as a service
Software that customers use through the provider's servers, here by connecting their own systems to the platform.

Technologies covered

  • PHP
  • Laravel
  • PostgreSQL
  • Redis
  • OpenTelemetry
  • OAuth 2.0

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

The core API at the centre, fed by storage, address, face and preview services, with documents sent across a boundary to an external signing platform

The Laravel core of a civil-service personnel system: employee records and career histories, self-service proposals with review, salary-step, promotion and retirement decisions, rules taken from regulations, a versioned organisation chart, and access scoped down to a single unit.

11 min read Read more →
A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

The Vue browser application of a document-signing platform: sessions held in memory and renewed by one queued refresh, PKCE sign-in, stamps placed precisely on PDF pages, identity checks with a face challenge, client consent, and role-based administration.

10 min read Read more →
A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

The digital signature platform of the City Government of South Tangerang: signers prove who they are, sign PDFs to PAdES B-LTA with certificates from the platform's own authorities, and anyone can verify the result — version 2, which I designed, built and operate.

10 min read Read more →

Related Articles

A memory chip holding a key, circled by refresh arrows, beside a browser window where a signature stamp is being dragged into place on a PDF page

The Vue browser application of a document-signing platform: sessions held in memory and renewed by one queued refresh, PKCE sign-in, stamps placed precisely on PDF pages, identity checks with a face challenge, client consent, and role-based administration.

10 min read Read more →
A signed PDF with a QR stamp, wrapped in four nested frames for the signature, its timestamp, the embedded validation data, and the archive timestamp

A Python service that signs PDFs to PAdES B-LTA with a visible stamp — embedding the timestamp, certificates, and revocation proof, then an archive timestamp — so signatures stay verifiable long after their certificates expire, and verifies signed PDFs.

10 min read Read more →
A document's fingerprint passing through a clock, signed by a certificate below it, and returning as a time seal stamped on the same document

A Rust timestamp authority that stamps a document's hash with a signed, NTP-backed time per RFC 3161, so PDF signatures stay verifiable after their certificates expire — issuing and renewing its own signing certificate, with public OCSP and CRL.

9 min read Read more →