Skip to content

Plan 06 limen side resource authentication backend - #30

Merged
PianoNic merged 14 commits into
mainfrom
feature/29_Plan06LimenSideResourceAuth
Apr 16, 2026
Merged

Plan 06 limen side resource authentication backend#30
PianoNic merged 14 commits into
mainfrom
feature/29_Plan06LimenSideResourceAuth

Conversation

@PianoNic

Copy link
Copy Markdown
Member

Summary

  • ResourceAuthPolicy, AllowlistedEmail, MagicLink (TokenHash stored, not plaintext), IssuedToken entities + EF migration
  • Ed25519 JWT signing via NSec.Cryptography with file-persisted key (owner-only perms on Unix, corrupt-key handling)
  • Argon2id password hashing via Konscious (PHC format, timing-equalized login path)
  • Magic link sender via MailKit with opt-in dev log fallback (LogMagicLinksInDev)
  • JwtBuilder produces 15-min EdDSA tokens with jti/sub/routeId/authMethod/cookieScope/iss/aud/iat/exp claims
  • 7 commands + 3 queries (SetResourceAuthPolicy, LoginWithPassword, InitiateMagicLink, VerifyMagicLink, InitiateResourceOidc, HandleResourceOidcCallback, RevokeToken, GetRevokedTokens, GetSigningPublicKey, GetResourceAuthPolicy)
  • ResourceAuthEndpoints: login-password, magic-request, magic verify, resource-oidc (501 placeholder), revoked, public-key, refresh, signout, admin/revoke
  • Auth-policy GET/POST admin routes on RoutesEndpoints
  • Magic-link double-use race closed via conditional UPDATE (ExecuteUpdateAsync)
  • ResourceOidcStateStore hard-capped, XML-doc notes single-instance limitation
  • AuthSettings validator + CookieSecure flag for dev HTTP
  • /auth/refresh and /auth/signout now verify JWT signature before honoring cookie claims
  • 45 unit tests passing

Ostiarius middleware and frontend policy editor are follow-up PRs.

Closes #29

PianoNic added 14 commits April 16, 2026 08:06
Adds ResourceAuthPolicy, AllowlistedEmail, MagicLink, IssuedToken
entities with EF configurations and ResourceAuth migration covering
the four new tables.
Adds NSec (Ed25519), Konscious.Security.Cryptography (Argon2id),
and MailKit packages to Limen.Infrastructure.
Implements ITokenSigner (Ed25519TokenSigner), IPasswordHasher
(Argon2IdPasswordHasher), IMagicLinkSender (MagicLinkSender), and
IResourceOidcStateStore (ResourceOidcStateStore) with their interfaces,
AuthSettings options, and JwtBuilder service.
Registers Ed25519TokenSigner, Argon2IdPasswordHasher, MagicLinkSender,
ResourceOidcStateStore, and JwtBuilder in AddInfrastructure.
Adds CQRS handlers for password login, magic link initiation and
verification, resource OIDC initiation and callback, token revocation,
and queries for revoked tokens, signing public key, and auth policy.
Adds ResourceAuthEndpoints with login-password, magic link, refresh,
signout, revoked tokens, public key, resource-oidc stub, and admin
revoke routes. Adds auth-policy GET and POST to RoutesEndpoints.
Adds unit tests for SetResourceAuthPolicyCommand, LoginWithPasswordCommand,
VerifyMagicLinkCommand, GetRevokedTokensQuery, Ed25519TokenSigner, and
Argon2IdPasswordHasher. 22 new tests, all green.
Add Verify method to ITokenSigner and implement in Ed25519TokenSigner.
Call signer.Verify at the top of /auth/refresh and /auth/signout before
trusting any cookie claims. Remove dead ?? fallbacks for authMethod and
cookieScope. Add Verify_AcceptsValidJwt, Verify_RejectsTamperedPayload,
and Verify_RejectsMalformedJwt tests to Ed25519TokenSignerTests.
When SMTP is not configured, throw InvalidOperationException unless
Auth:LogMagicLinksInDev is explicitly set to true. Demote the log call
to LogDebug with a comment marking it as an OPERATOR-VISIBLE dev fallback
that must never be used in production. Add LogMagicLinksInDev (default
false) and CookieSecure (default true) to AuthSettings.
Replace tracked UsedAt assignment with ExecuteUpdateAsync conditioned on
UsedAt == null. Add SupportsBulkUpdate to IAppDbContext so handlers can
fall back to the tracker-based update when running against the in-memory
provider in tests.
Throw InvalidOperationException at the top of InitiateMagicLinkCommand
handler when AuthSettings.PublicBaseUrl is missing. Also add
AuthSettingsValidator (IValidateOptions<AuthSettings>) that fails startup
if SigningKeyPath is absent, registered via AddApplication.
Add MaxEntries cap of 10,000 and PruneExpired helper called on each Put.
Throw InvalidOperationException if the store is at capacity after
pruning. Add XML doc noting the store is single-instance only.
Call _hasher.Verify against a dummy Argon2id hash and discard the result
when the policy is absent, so the response time does not leak whether a
route has password auth configured.
Replace int.Parse with int.TryParse for each PHC parameter field and log
a structured warning on parse failure instead of silently returning false.
Add ILogger<Argon2IdPasswordHasher> constructor dependency. Update test
to pass NullLogger.
@PianoNic
PianoNic merged commit bcb3400 into main Apr 16, 2026
2 checks passed
@PianoNic
PianoNic deleted the feature/29_Plan06LimenSideResourceAuth branch April 16, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Plan 06 limen side resource auth backend

1 participant