Ownware
Home›Certora›Manual
Certora · Manual

Certora Manual, as shipped in the download

Certora — User Manual

Certificates issued from templates, with a public verification page. Version 3.1.4 [src: app/controllers/api.php:23].

About this manual

Every statement here was written by reading Certora's own source, and each one carries the file it came from in a bracketed src marker. Paths are relative to the folder this docs directory sits in. If a sentence disagrees with the application, the application is right and this manual has a bug — the markers exist so you can check rather than take our word for it.

Nothing is described that the code does not do. Where something is deliberately limited, that is said plainly rather than left out.

⚠️ What a verification code is — and what it is not

This is the most important thing in the product, and the source states it without softening [src: app/src/Cert.php:10]:

Verification codes are plain lookup tokens. A code is random alphanumeric text that is unique in the certificates table — nothing more. It is not a signature, an HMAC, or any cryptographic key: verification is a database lookup of the code, never a signature check. Certora issues no keys, signs nothing, and has zero crypto surface.

What that means in practice, stated plainly because a certificate product invites the opposite assumption:

A verified code proves that this installation issued that certificate and has not revoked it. It does not prove the certificate document in front of you is unaltered, because nothing is signed. Somebody could reprint the face with different wording and the code would still verify — what verification returns is your record, not their paper.

Used the right way round, that is exactly what you want: the verifier reads the truth from your database rather than trusting the document. Just do not describe it as a digital signature, because it is not one.

Verification codes

Twelve characters from an alphabet of uppercase letters and digits with the ambiguous ones removed — no 0/O, no 1/I/L — so a printed code is easy to read back and type in [src: app/src/Cert.php:26].

That gives roughly 7.8 × 10¹⁷ possibilities, which the source notes makes collisions astronomically unlikely [src: app/src/Cert.php:30].

Uniqueness is guaranteed rather than assumed. Generation retries against a database check, and after a number of attempts it lengthens the code rather than looping forever [src: app/src/Cert.php:82].

A typed code is forgiving on the way in. Spaces, dashes and anything outside the alphabet are stripped and the result upper-cased, so abcd-1234-wxyz and ABCD 1234 WXYZ both resolve to the stored form [src: app/src/Cert.php:103]. Display groups it back into fours for printing [src: app/src/Cert.php:115].

The certificate PDF

The signatory title and the "Issued … Valid until …" line print at 10 pt [src: app/src/PdfCert.php:315]. Before 3.1.4 a number-formatting fault set both at 1 pt, so a certificate's own dates and the signatory's title were specks on the paper.

When a public verify address is set in Settings, the certificate carries its verify link as a QR code, bottom right, one inch square [src: app/src/PdfCert.php:193], so an employer can scan rather than type the code. A revoked certificate carries none [src: app/controllers/app.php:614]. The encoder is the one Assetora uses, and the suite reads every symbol back with an independent decoder. If a footer line is too long to sit beside the code even at 7 pt, the code is left off and the text keeps its size [src: app/src/PdfCert.php:163].

The public verification page

No sign-in is required [src: app/controllers/app.php:865]. Three things protect it, and one thing limits what it reveals:

  • A per-address fixed-window throttle, computed as a pure function so it can be tested without a clock or a database [src: app/src/Cert.php:126].
  • A honeypot field [src: app/controllers/app.php:866].
  • An unknown code returns 404 and never reveals whether a code was merely mistyped [src: app/controllers/app.php:867].
  • Only the certificate face is shown — recipient, course, template, issuer, issue date, validity. No email address, no administrative data [src: app/controllers/app.php:868].

Status: revoked beats expired beats valid

One function decides the displayed status, and every surface derives from it — the public verify page, the register, the dashboard and the CSV export [src: app/src/Cert.php:215].

The precedence is explicit: revoked wins over expired, which wins over valid [src: app/src/Cert.php:214].

A certificate is valid through its expiry date [src: app/src/Cert.php:203] — expired means today is past it, not on it. A certificate with no expiry never expires [src: app/src/Cert.php:208].

Month arithmetic is clamped

An expiry of "issued plus one month" from 31 January lands on 28 February, never rolling silently into March — which is what PHP's native month addition would do [src: app/src/Cert.php:186].

The source notes this is the same clamp rule already shipped in two sibling products [src: app/src/Cert.php:188], which is the right way to handle a trap that has caught somebody before.

Templates and merge tokens

A template body may contain five merge tokens: recipient, course, date, issuer and code [src: app/src/Cert.php:20], substituted at issue [src: app/src/Cert.php:43]. The tokens actually used in a given template can be listed [src: app/src/Cert.php:56].

Certificates are landscape or portrait, with anything unrecognised falling back to landscape rather than failing [src: app/src/Cert.php:226].

Users and roles

Three roles: viewer, registrar, admin [src: app/src/Auth.php:32].

A registrar is "the job this product exists for" — loading recipients, running issue batches, revoking and reinstating certificates — and cannot edit templates or settings [src: app/src/Auth.php:15]. A viewer is the rung for an auditor, or for whoever fields "is this real?" calls [src: app/src/Auth.php:14].

Why the middle role is not called "issuer"

A small naming decision with a good reason behind it [src: app/src/Auth.php:19]: the issuer setting already means the organisation printed on the certificate face, and two different meanings of one word on one screen is how a permission gets granted by accident.

Why templates are admin-only

Again a specific reason rather than a generic one [src: app/src/Auth.php:23]: a template owns the title, the signatory and the validity period — what the certificate claims and how long it stands. Editing it changes what every future certificate asserts on somebody else's behalf, which is an owner's decision.

Certificates already issued are untouched either way, because the face and the expiry are snapshotted at issue [src: app/src/Auth.php:26]. Changing a template does not rewrite history.

The audit trail is granted to a viewer explicitly — audit.view is named in the viewer's list rather than arriving through the wildcard [src: app/src/Auth.php:32].

The API and agent access

Six tools are exposed to an agent [src: app/controllers/v3.php:70]: listing templates, template detail, listing certificates, an expiring report and verifying a certificate on the read side; issuing certificates on the write side.

The agent endpoint reports the same version as the rest of the product [src: app/controllers/v3.php:69].

What Certora does not do

It does not sign anything [src: app/src/Cert.php:10]. There is no key, no HMAC and no cryptographic surface at all.

It does not prove a document is unaltered. It proves what your register says about a code.

It does not tell a stranger whether a code was mistyped [src: app/controllers/app.php:867].

It does not expose anything beyond the certificate face on the public page [src: app/controllers/app.php:868].

It does not rewrite issued certificates when a template changes [src: app/src/Auth.php:26].

It does not roll a month-end expiry into the next month [src: app/src/Cert.php:186].

← Back to Certora · Quickstart · API · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →