The endpoint was a copy-paste from the IdentityServer template
documentation. It serialised the entire HttpContext.User claim set
to anonymous JSON, with no auth gate. In a public-facing deployment
that's exactly the kind of surface scrapers and botnets love
(it tells them whether their token is valid and what shape the
issuer uses), and it served no production purpose.
Side benefit: removes the ASP0004 analyser warning ("IActionResult
should not be returned from a MapGet Delegate") that came with
this line.
All [ApiController] classes (BlogApi, BlogTags, PostTags, FileSystem,
FileSystemStream, Comments, TagsApi) returned 404 on every route,
even though Kestrel was up. The pipeline in Program.cs was missing
MapControllers(), so the controllers were never attached to the
endpoint data source. MapIdentityApi and MapGet("/identity")
worked because they're explicit minimal-API routes; the attribute-
routed controllers didn't.
Confirmed end-to-end: GET /api/v1/blog now returns 401 (auth
required by [Authorize("BlogScope")]) instead of 404.
Narrow ISmtpClient to the four operations MailSender actually uses,
behind a Yavsc.Interfaces.ISmtpClientFactory. Production wires
MailKitSmtpClient (SmtpClientFactory); tests wire a recording fake
(RecordingSmtpClientFactory). The fake is pre-registered in
WebServerFixture so SMTP calls are short-circuited; the EMailling
test now asserts the Connect -> Authenticate -> Send -> Disconnect
sequence. Yavsc.Abstract stays free of MailKit/MimeKit.
The Site:Audience setting was conflating two distinct concepts: an OAuth
JWT audience (a single resource identifier) and a CORS allow-list (an
array of origins). Collapsing them caused several latent bugs:
- OAuth/JWT validation expected a single string while CORS WithOrigins
accepts an array.
- Password-reset callback URLs and OAuth client RedirectUri/Origin were
being built from what was meant to be an audience identifier, not a
base URL.
- Yavsc.Org's main CORS policy was hardcoded to '*', with no way to
restrict it without code changes.
Changes:
- SiteSettings.Audience (string) replaced with CorsAllowedOrigins
(IList<string>).
- OAuth JWT Authority still reads Site:Authority; Audience now reads
Site:ExternalUrl (Org only; Api/Blogs use ValidateAudience=false).
- MailSender and AccountController build reset-callback URLs from
Site:ExternalUrl.
- ClientController uses Site:ExternalUrl for OAuth RedirectUri/Origin
defaults on newly created clients.
- Yavsc.Api and Yavsc.Blogs now read CORS origins from
Site:CorsAllowedOrigins instead of hardcoded URLs.
Add shared AddYavscCors / AddYavscJwtBearer extension methods in
Yavsc.Server/Helpers/ServiceExtensions.cs to enforce a single
configuration contract across all runtime services (Api, Blogs, Org).
Fails closed when CorsAllowedOrigins is empty; fails fast at startup
when Site:Authority is missing.
Remove obsolete ConfigurationHelpers.GetAudience (no remaining callers).
Local appsettings-*.json files (which carry deployment-specific values
and are gitignored) must be updated to add Site:CorsAllowedOrigins.