verifyAuthRuntimeConformance function

Future<void> verifyAuthRuntimeConformance({
  1. required Uri origin,
  2. required AuthRuntimeConformanceSend send,
  3. bool sendValidOriginHeader = true,
})

Verifies auth behavior through an arbitrary HTTP host transport.

This utility intentionally has no dependency on package:test. Test suites can call it from any test framework and treat an AuthRuntimeConformanceFailure as a failed assertion.

Implementation

Future<void> verifyAuthRuntimeConformance({
  required Uri origin,
  required AuthRuntimeConformanceSend send,
  bool sendValidOriginHeader = true,
}) async {
  final validOriginHeader = sendValidOriginHeader ? origin.toString() : null;
  final csrfResponse = await send(
    const AuthRuntimeConformanceRequest(method: 'GET', path: '/auth/csrf'),
  );
  _check(
    csrfResponse.statusCode == 200,
    'csrf.issue',
    'Expected status 200, received ${csrfResponse.statusCode}.',
  );
  final csrfBody = _jsonObject(csrfResponse, 'csrf.issue');
  final csrfValue = csrfBody['csrfToken'];
  final csrf = switch (csrfValue) {
    final String value when value.isNotEmpty => value,
    _ => throw const AuthRuntimeConformanceFailure(
      caseId: 'csrf.issue',
      message: 'Expected a non-empty csrfToken.',
    ),
  };

  final initialSetCookie = _setCookieFor(
    csrfResponse,
    authRuntimeConformanceCookieName,
  );
  final lowerCookie = initialSetCookie.toLowerCase();
  _check(
    lowerCookie.contains('httponly'),
    'cookie.policy',
    'Session cookie must be HttpOnly.',
  );
  _check(
    lowerCookie.contains('samesite=lax'),
    'cookie.policy',
    'Session cookie must use SameSite=Lax.',
  );
  _check(
    lowerCookie.contains('path=/'),
    'cookie.policy',
    'Session cookie must use Path=/.',
  );
  _check(
    !lowerCookie.contains('secure'),
    'cookie.policy',
    'Development fixture cookie must not be Secure.',
  );
  var cookie = _cookiePair(initialSetCookie);

  final invalidOrigin = await send(
    AuthRuntimeConformanceRequest(
      method: 'POST',
      path: '/auth/signin/credentials',
      headers: _requestHeaders(
        cookie: cookie,
        origin: 'https://attacker.example',
      ),
      body: _credentialsBody(csrf: csrf),
    ),
  );
  _expectError(
    invalidOrigin,
    caseId: 'browser.invalid-origin',
    statusCode: 403,
    error: 'invalid_origin',
  );

  final crossSite = await send(
    AuthRuntimeConformanceRequest(
      method: 'POST',
      path: '/auth/signin/credentials',
      headers: _requestHeaders(cookie: cookie, fetchSite: 'cross-site'),
      body: _credentialsBody(csrf: csrf),
    ),
  );
  _expectError(
    crossSite,
    caseId: 'browser.cross-site',
    statusCode: 403,
    error: 'cross_site_request',
  );

  final invalidCsrf = await send(
    AuthRuntimeConformanceRequest(
      method: 'POST',
      path: '/auth/signin/credentials',
      headers: _requestHeaders(cookie: cookie, origin: validOriginHeader),
      body: _credentialsBody(csrf: 'invalid'),
    ),
  );
  _expectError(
    invalidCsrf,
    caseId: 'csrf.reject-invalid',
    statusCode: 403,
    error: 'invalid_csrf',
  );

  final signIn = await send(
    AuthRuntimeConformanceRequest(
      method: 'POST',
      path: '/auth/signin/credentials',
      headers: _requestHeaders(cookie: cookie, origin: validOriginHeader),
      body: _credentialsBody(csrf: csrf),
    ),
  );
  _check(
    signIn.statusCode == 200,
    'credentials.sign-in',
    'Expected status 200, received ${signIn.statusCode}: ${signIn.body}',
  );
  final signInBody = _jsonObject(signIn, 'credentials.sign-in');
  _check(
    _userId(signInBody) == authRuntimeConformanceUserId,
    'credentials.sign-in',
    'Sign-in response did not contain the conformance user.',
  );
  final updatedSetCookie = _optionalSetCookieFor(
    signIn,
    authRuntimeConformanceCookieName,
  );
  if (updatedSetCookie != null) cookie = _cookiePair(updatedSetCookie);

  final session = await send(
    AuthRuntimeConformanceRequest(
      method: 'GET',
      path: '/auth/session',
      headers: <String, List<String>>{
        'cookie': <String>[cookie],
      },
    ),
  );
  _check(
    session.statusCode == 200,
    'session.read',
    'Expected status 200, received ${session.statusCode}.',
  );
  final sessionBody = _jsonObject(session, 'session.read');
  _check(
    _userId(sessionBody) == authRuntimeConformanceUserId,
    'session.read',
    'Session response did not preserve the authenticated user.',
  );

  final freshCsrf = await send(
    AuthRuntimeConformanceRequest(
      method: 'GET',
      path: '/auth/csrf',
      headers: <String, List<String>>{
        'cookie': <String>[cookie],
      },
    ),
  );
  _check(
    freshCsrf.statusCode == 200,
    'error.sanitization',
    'Could not refresh the CSRF token before the failure request.',
  );
  final failureCsrf = _jsonObject(freshCsrf, 'error.sanitization')['csrfToken'];
  _check(
    failureCsrf is String && failureCsrf.isNotEmpty,
    'error.sanitization',
    'Expected a fresh CSRF token.',
  );
  final failure = await send(
    AuthRuntimeConformanceRequest(
      method: 'POST',
      path: '/auth/signin/credentials',
      headers: _requestHeaders(cookie: cookie, origin: validOriginHeader),
      body: jsonEncode(<String, Object?>{
        'email': 'explode@example.test',
        'password': authRuntimeConformancePassword,
        '_csrf': failureCsrf,
      }),
    ),
  );
  _check(
    failure.statusCode == 500,
    'error.sanitization',
    'Expected status 500, received ${failure.statusCode}.',
  );
  _check(
    !failure.body.contains(authRuntimeConformanceFailureMarker) &&
        !failure.body.contains('/srv/secrets'),
    'error.sanitization',
    'Internal error details leaked into the response body.',
  );
  _check(
    failure.body.toLowerCase().contains('unexpected error'),
    'error.sanitization',
    'Expected the generic unexpected-error response.',
  );
}