Security model
HridaSign holds documents people rely on being unaltered, and links that let a stranger act on one. The controls reflect that.
Authentication
- Passwords — BCrypt, never stored or logged in the clear.
- Sessions — stateless JWT signed with
JWT_SECRET.JwtAuthenticationFiltervalidates every non-public request;/api/auth/**and/api/public/**are the only open paths. - Platform admins authenticate against a separate
admin_accountstable, so operator credentials are not on the surface tenants use. Bootstrapping the first one needsADMIN_SETUP_KEY.
Signing links and OTP
- A recipient's link carries a UUID token, but only its SHA-256 hash (
tokenHash) is stored — a database dump yields no working links. - The email OTP is stored as a SHA-256 hash with an expiry and an attempt counter, and every send / verify / failure is written to the audit trail.
Document integrity
Every completed document carries a SHA-256 fingerprint over its title, source file, signed field values and recipient metadata. GET /api/sign/{docId}/integrity recomputes and compares it, and a mismatch is reported as TAMPERED and logged. See Document integrity & audit.
Tenant isolation
Every organization record — properties, real-estate documents, signatures, templates, team — is scoped to its organization_id. A user with no org sees only their own files and signing documents. ROLE_PLATFORM_OWNER is the only role that reads across tenants, and it's a distinct login.
File ownership
A file_metadata row has one owner. Download, delete and use are the owner's alone. Deleting the row deletes the file on disk; a file backing an active sign document is protected from deletion.
Redaction removes, it doesn't hide
The redact tool deletes matched terms from the PDF content rather than drawing a black box over still-present text — so the redacted words aren't recoverable by selecting under the mark.
API keys
An enterprise API key is stored as a SHA-256 hash with only a short display prefix retained. The raw key is shown once.
Operational guidance
- Run behind a TLS-terminating reverse proxy; the container binds
127.0.0.1. - Generate
JWT_SECRETandADMIN_SETUP_KEYfresh per environment; never copy from an example file. - Keep
CORS_ALLOWED_ORIGINStight. - Set Hibernate
ddl-autotovalidateon a stable production schema. - Guard the Razorpay webhook with
RAZORPAY_WEBHOOK_SECRET.