Security
Enforced by structure, not by remembering.
Authentication is applied through shared dependencies rather than route by route. Secrets live in a managed store. Input is validated at every boundary. The design intent is that the secure path is the default path, not the disciplined one.
Identity and access
Credentials are hashed with Argon2id — never stored reversibly, never written to logs. Login issues a short-lived access token alongside a longer-lived refresh token that rotates when used, so a leaked access token has a small window and a leaked refresh token does not survive being replayed.
Access tokens are JWTs signed with ES256 against a key that rotates on a schedule, not a static secret held indefinitely. Products verify tokens against the published, current key and never hold the signing key itself, which means a compromised product backend cannot mint credentials for the rest of the ecosystem. Social login and Oidot's own OIDC provider role both run the standard OAuth 2.1 authorization-code flow with PKCE, state, and nonce — not a simplified variant.
Access control is role-based and permission-based rather than a hardcoded list of role names, and it fails closed: a permission that isn't explicitly granted is treated as absent, not as an edge case handled later. Every authentication and password-reset endpoint is enumeration-safe — the response is identical whether or not an account exists, so an attacker can't use error messages to build a list of valid emails.
Application security
Every request body, query parameter, and path parameter is validated against a schema at the boundary, before it reaches any domain logic. Database access goes through an ORM with parameterised queries; SQL is never assembled by string interpolation. Cross-origin access is restricted to known origins rather than left open, and state-changing requests are protected against CSRF by default.
Authentication is applied as a dependency shared across routes, so a new endpoint is protected by default rather than protected if the author remembers. Rate limiting is applied across the API, with tighter limits on authentication endpoints specifically, where brute force is the realistic threat.
Infrastructure and secrets
The database sits in a private subnet, reachable only from the API's own security group. TLS terminates at the load balancer, the only internet-facing component. Encryption at rest is enabled on the managed database.
Secrets — database credentials, token signing keys — are held in a managed secret store and injected at runtime. They are never baked into a container image or committed to the repository. Every role follows least privilege rather than being granted broad access for convenience.
Containers run from minimal base images as a non-root user, and images are scanned before they are pushed.
How this stays true
Dependency vulnerabilities are scanned automatically in the pipeline, so a known-vulnerable package fails a build rather than waiting for someone to notice. Tests cover authentication and authorisation paths including the negative cases — wrong password, expired token, insufficient role — because those are the paths that matter when something goes wrong.
Writes to sensitive records are logged with actor, action, and time. Structured logs are emitted from the first deployment so they remain queryable as volume grows.
A compromised product cannot forge platform identity
Product backends hold only the public key needed to verify tokens. They cannot issue one. In a system where several products share one identity layer, this is the difference between a contained incident and an ecosystem-wide one.
Oidot is an early-stage company. This page describes how the platform is built and the practices we hold ourselves to — not a completed certification programme. If you are evaluating us for a specific compliance requirement, ask, and we will tell you plainly where we stand.
Ask us anything specific
If you are evaluating Oidot against a security or compliance requirement, tell us what you need to see and we will give you a direct answer about where we are.