Add JWT Bearer authentication backed by AWS Cognito#140
Add JWT Bearer authentication backed by AWS Cognito#140jodavis wants to merge 6 commits intofeature/ADR-161-cusrtomization-servicefrom
Conversation
…nd auth API tests - CompiledLayoutService: add JWT Bearer authentication backed by AWS Cognito. GET /layouts/compiled/active now requires a valid bearer token; GET /health remains unauthenticated. The sub claim is extracted as userId. CognitoSettings reads Authority and Audience from appsettings/env vars. - Client app: add BackendSettings, ICognitoTokenService, CognitoTokenService. CognitoTokenService acquires and caches tokens via the OAuth2 Client Credentials flow (lazy acquire, 60-second expiry buffer). Log messages in range 1600-1699. - API tests: add TestJwtAuthority (local OIDC/JWKS server) so auth can be tested end-to-end without a real Cognito user pool. ServiceFixture now starts the authority first and configures Cognito__Authority on the service process. CommonSteps updated to use Reqnroll context injection (ServiceContext) for shared fixture state. AuthenticationEndpoints.feature covers 401 for no-auth and expired tokens, 200 for valid JWT, and unauthenticated /health access. - Docs: _doc_Auth.md documents Cognito setup for local dev, client credentials config, editor Authorization Code flow, and the test JWT authority pattern. https://claude.ai/code/session_01LLWQBraEp7n7uLVy7M4PFp
327624c to
787b0df
Compare
|
@claude -- The API tests are hanging with these changes. Debug the problem, describe what's happening, and try to fix it. When you're done, the solution should build without warnings or errors and all tests should pass, especially the Headless Host E2E tests and API tests. |
…nd auth API tests - CompiledLayoutService: add JWT Bearer authentication backed by AWS Cognito. GET /layouts/compiled/active now requires a valid bearer token; GET /health remains unauthenticated. The sub claim is extracted as userId. CognitoSettings reads Authority and Audience from appsettings/env vars. - Client app: add BackendSettings, ICognitoTokenService, CognitoTokenService. CognitoTokenService acquires and caches tokens via the OAuth2 Client Credentials flow (lazy acquire, 60-second expiry buffer). Log messages in range 1600-1699. - API tests: add TestJwtAuthority (local OIDC/JWKS server) so auth can be tested end-to-end without a real Cognito user pool. ServiceFixture now starts the authority first and configures Cognito__Authority on the service process. CommonSteps updated to use Reqnroll context injection (ServiceContext) for shared fixture state. AuthenticationEndpoints.feature covers 401 for no-auth and expired tokens, 200 for valid JWT, and unauthenticated /health access. - Docs: _doc_Auth.md documents Cognito setup for local dev, client credentials config, editor Authorization Code flow, and the test JWT authority pattern. https://claude.ai/code/session_01LLWQBraEp7n7uLVy7M4PFp
Three categories of fixes:
1. API tests hanging: ServiceFixture.StartService() was blocking the async
test thread with Thread.Sleep() and HttpClient.GetAsync().Result, risking
a deadlock when called from Reqnroll's async step dispatcher. Renamed to
StartServiceAsync(), switched to await/Task.Delay, added a 5-second per-
request timeout on the health-check client, and made the [Given] step
binding async. The service URL is now allocated on a dynamic free port
instead of hardcoded :5000, eliminating port-conflict failures between
consecutive scenarios.
2. Build errors:
- Removed 'using System.Net.Http;' from CognitoTokenService.cs — the
namespace is already a global implicit using for Microsoft.NET.Sdk.Razor
and the redundant directive triggers a warning/error with /warnaserror.
- Changed <Content Include="appsettings*.json"> to <Content Update=...> in
AdaptiveRemote.csproj so we only set CopyToOutputDirectory metadata on
items the SDK already includes automatically, instead of adding duplicate
Content items.
3. Missing package: Added Microsoft.NET.Test.Sdk to AdaptiveRemote.Backend.
ApiTests.csproj — required by Reqnroll.MSTest for proper test-host
infrastructure (consistent with all other test projects in the solution).
https://claude.ai/code/session_01LLWQBraEp7n7uLVy7M4PFp
|
@copilot There are two problems with the build in this branch. One is a package mismatch error that is causing the build to fail. The other is that we're running E2E tests even when there's a build failure. The latter problem is because of an Please fix these issues and any others until the build passes without warnings or errors and all tests pass, especially the E2E and API tests. |
… gating Three build fixes: 1. Package mismatch (NU1608): Replace MSTest meta-package with MSTest.TestAdapter + MSTest.TestFramework in ApiTests project. MSTest 3.1.1 meta-package requires Microsoft.NET.Test.Sdk = 17.6.0 exactly, which conflicts with the 18.0.1 version in Directory.Packages.props. Other test projects already use the individual packages to avoid this. 2. Code analysis error (CA1816): Add GC.SuppressFinalize(this) to ServiceContext.Dispose() as required by CA1816. 3. Workflow: Add id: build to the Build step and change E2E Tests from if: always() to if: always() && steps.build.outcome == 'success'. This ensures E2E tests skip when the build fails, but still run when only unit tests fail (as was the intent of always()). Agent-Logs-Url: https://github.com/jodavis/AdaptiveRemote/sessions/d7976913-3a8a-4c5f-b6ce-5f024fe07d01 Co-authored-by: jodavis <6740581+jodavis@users.noreply.github.com>
Fixed in commit
The API tests were hanging due to a build failure — once the build fails, the E2E test runner ( |
|
@copilot The API tests are still failing in CI runs. I'm not sure why. It's reporting that the service didn't start within 30s, but the process logs look like it was started and waiting for requests. Investigate and see if you can fix those as well. Add logging to the test if needed to understand why the test thinks the server isn't started yet. |
…ettings from overriding ASPNETCORE_URLS Root cause: dotnet run reads launchSettings.json and overwrites ASPNETCORE_URLS with applicationUrl (https://localhost:54433;http://localhost:54434), ignoring the dynamic port set in ProcessStartInfo.Environment. The health check polls the dynamic port but the service listens on 54434, so it always times out. Changes: 1. ServiceFixture.cs: Added --no-launch-profile to dotnet run so ASPNETCORE_URLS from the test fixture's environment is respected. 2. ServiceFixture.cs: Added per-attempt diagnostic logging in the health check loop showing the URL polled and the status/exception per attempt. 3. Program.cs: Fixed misleading ServiceStarted log — app.Urls is always empty before Run(), so read ASPNETCORE_URLS from IConfiguration instead. Agent-Logs-Url: https://github.com/jodavis/AdaptiveRemote/sessions/ba6750ee-d018-4f28-b4d0-7d4e309d6f02 Co-authored-by: jodavis <6740581+jodavis@users.noreply.github.com>
Fixed in commit Three changes:
|
Summary
Implements JWT Bearer token authentication for the CompiledLayoutService backend API using AWS Cognito as the identity provider. The service now validates bearer tokens on protected endpoints and extracts the
subclaim as the user ID. Includes a local test JWT authority for API integration tests to validate authentication flows end-to-end without external dependencies.Key Changes
Backend Service (CompiledLayoutService)
CognitoSettingsconfiguration class to manage Authority and Audience settings/layouts/compiled/activeendpoint with[Authorize];/healthremains unauthenticateduserIdfrom the JWTsubclaim and passed it to the layout repositoryCognito__AuthorityandCognito__Audienceenvironment variablesClient Application (AdaptiveRemote)
CognitoTokenServiceto acquire and cache OAuth2 access tokens using the Client Credentials flowBackendSettingsandCognitoClientSettingsconfiguration classes for backend connectivityBackendHostBuilderExtensionsappsettings.jsonandappsettings.Development.jsonwith Cognito configuration placeholdersAPI Integration Tests
TestJwtAuthority: a minimal local OIDC/JWKS server that issues and validates test JWTs/.well-known/openid-configurationand/.well-known/jwks.jsonendpointsServiceFixtureto start the test JWT authority before the serviceCreateToken(),CreateExpiredToken(),CreateAnonymousHttpClient(),CreateBearerHttpClient()ServiceContextfor Reqnroll scenario-scoped dependency injectionAuthenticationStepswith step definitions for testing authenticated/unauthenticated/expired token scenariosAuthenticationEndpoints.featurewith four test scenarios covering the authentication matrixDocumentation
_doc_Auth.mdwith comprehensive authentication architecture, Cognito setup instructions, and configuration guidance for both client and backendNotable Implementation Details
Cognito__Audienceis empty, validation is skippedhttps://claude.ai/code/session_01LLWQBraEp7n7uLVy7M4PFp