Operational guide for AI agents (Claude Code, Cursor, Copilot, …) working in this repo. Humans: see README.md and docs/. Keep this file short and high-signal — it is loaded into limited context.
Altinn Platform Authentication — an ASP.NET Core (.NET 10) service that authenticates users/orgs/systems and issues Altinn JWTs, and acts as a small OIDC authorization server for browser sign-in. Read docs/architecture.md first.
# Build
dotnet build Altinn.Platform.Authentication.sln
# Test (Docker MUST be running — Testcontainers PostgreSQL)
dotnet test test/Altinn.Platform.Authentication.Tests/Altinn.Platform.Authentication.Tests.csproj
# Compile-only check of one project (fast)
dotnet build src/Authentication/Altinn.Platform.Authentication.csproj -clp:ErrorsOnly --nologo- A green local
dotnet buildis NOT sufficient. The integration tests need Docker, and compilation passing says nothing about them. The authoritative gate is the CI Build and Test job. If you can't run Docker, push and watch CI before claiming done. - Branch per change; never commit to
main. Commit/push only when asked. - Update the relevant
docs/page or ADR in the same PR as a behaviour change. - Respond to CodeRabbit/CodeQL review comments; don't silently ignore them.
src/Authentication— host, controllers, app services, config.src/Core— models/interfaces/pure helpers (no I/O).src/Integration— outbound clients (Register/PartiesClient, Access Management, Profile).src/Persistance— Postgres + SQL migrations.src/jwtcookie— shared JWT-cookie library.- Auth flows are documented in
docs/flows/. The why behind the design is indocs/adr/— read the relevant ADR before changing an auth flow.
AuthenticateUserno longer branches onEnableOidc/ForceOidc/AuthorizationServerEnabled— those legacy browser-sign-in branches were collapsed in #2071 (ADR-0002); the authorization-server flow is the only live browser path. Don't reintroduce branching on these inAuthenticateUser. The settings still exist (checked-in valuefalse— not prod), with differing real usage:ForceOidc— still read inOidcServerService(session logic).AuthorizationServerEnabled— still read inLogoutController, which still has a legacy branch (dead only if prod sets ittrue; a collapse candidate like #2071).EnableOidc— now read nowhere; a dead property / safe-removal candidate.
IsSafeSameOrSubdomainHttps(AuthenticationController) is an intentional open-redirect guard. The CodeQL "URL redirection" alerts on thegoTo/upstream redirects are dismissed false positives — don't rewrite the redirects to appease a scanner.IsValidIssueris misnamed (returnstruefor an invalid issuer) but its control flow is correct. Fix the name/substring-match if asked, but do not "invert" the logic — that would break it.SblAuthCookie*names + the legacy-cookie delete logic are intentionally kept to drain stale Altinn 2 cookies, even though the rest of the SBL integration is gone (ADR-0004).- Token-validation in the exchange path disables issuer/audience checks — flagged for review in #2074; verify intent against tests before changing.
- Build Register contract types (
Altinn.Register.Contracts) via JSON deserialization in tests. APartyUserwithuserIdset must also setuserIds(e.g."userIds": [ <id> ]) or its constructor throws at runtime. - Mock outbound clients with a mocked
HttpMessageHandler(seeAccessManagementClientTests); unit-test pure logic directly (seeAuthenticationHelperTests).
A prioritised top-30 lives in #2074. Open follow-ups: #2072.