verifyAuthRuntimeConformance function
Future<void>
verifyAuthRuntimeConformance({
- required Uri origin,
- required AuthRuntimeConformanceSend send,
- 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.',
);
}