Design
Passwords, encryption, breach checks
Password hashing, encryption, HaveIBeenPwned helpers, an OAuth access-token mint, and a tenant authorization framework.
This is not a commercial Identity Provider. It is not Duende IdentityServer. Canonical positioning: what-this-is.md.
Published docs: https://novolis-platform.github.io/.github/novolis-security/
The end-state contract is REFACTORING_SPEC.md.
Layer placement
Follow library-boundaries for layer placement.
Goals
- Keep public APIs documented and packable as
Novolis.*on GitHub Packages. - Prefer BCL types and existing Novolis packages over parallel abstractions.
- Document restore and ProjectReference-mode builds without local NuGet folder feeds.
- Keep Authentication, OAuth, and Authorization as separate systems: sign-in, token mint, tenant authz.
Non-goals
- Local NuGet folder feeds or committed cross-repo
ProjectReferenceinto sibling checkouts. - Avalonia package references outside
Novolis.Avalonia.*. - Password grant, OpenID Connect, SAML, nested groups, or negative authorization rules.
- A full Identity Provider product: ID Tokens as login, userinfo, federation, admin UI, consent UI, dynamic client registration, PAR, JAR, CIBA, Device Code, or Token Exchange.
- Substituting for Duende IdentityServer, Keycloak, Auth0, Microsoft Entra ID, or similar commercial IdPs.
Packages
Novolis.Security.CryptographyNovolis.Security.EncryptionNovolis.Security.HaveIBeenPwnedNovolis.Security.PasswordHashingNovolis.Security.SecretsNovolis.Security.Authentication.*Novolis.Security.OAuth.*Novolis.Security.OAuth.Client— outbound Novolis-issuer caller. OneAddNovolisOAuthClient<TApi>registration per legal credential. InjectINovolisOAuthClient<TApi>. Refresh bindsTStoreto that client. Does not wrapNovolis.Http.Authentication.Novolis.Security.Authorization.*
Credential store isolation
The credential vault is not a user directory.
- Allowed on
CredentialRecord: opaqueCredentialReference, password hash, disabled flag, timestamps. - Forbidden on credential records:
IdentityId, email, username, phone, display name, tenant, group, or role data.
IdentityId is the JWT subject. CredentialReference never becomes a public identifier.
ICacheStore is the product cache: in-memory for tests and a single process, replaced with a distributed store when more than one process shares lockout, MFA, or OAuth leases.
IMfaProvider is a product second factor. The library default is NoopMfaProvider.
Authorization
Authorization is tenant-scoped. Groups contain identities. Roles contain permissions. Composite roles contain roles and must remain acyclic.
OAuth scopes are not application permissions.
OAuth mints access tokens. Authorization decides tenant capabilities. Neither package is an IdP user directory or a replacement for IdentityServer.