apiKeyAuthentication function
- required AuthApiKeyPlugin<
EngineContext> plugin, - required AuthUserStore userStore,
- String headerName = 'x-api-key',
- FutureOr<
void> onVerified(- EngineContext context,
- AuthApiKeyAuthentication authentication,
- AuthUser user
Authenticates requests carrying an API key.
The middleware accepts X-API-Key: <key> by default and also accepts
Authorization: ApiKey <key>. A missing key leaves the request untouched,
allowing applications to compose API-key, session, and JWT middleware. An
invalid supplied key returns a generic 401 response with an ApiKey
challenge. headerName is trimmed and must not be empty. After successful
user lookup, onVerified runs before next, and the request receives the
API-key authentication plus an AuthPrincipal with apiKeyId and
apiKeyScopes attributes. Invalid credentials do not disclose whether a
key or user exists; exceptions from the authentication plugin or user store
propagate to the surrounding middleware pipeline.
Throws an ArgumentError when headerName is empty after trimming.
Implementation
Middleware apiKeyAuthentication({
required AuthApiKeyPlugin<EngineContext> plugin,
required AuthUserStore userStore,
String headerName = 'x-api-key',
FutureOr<void> Function(
EngineContext context,
AuthApiKeyAuthentication authentication,
AuthUser user,
)?
onVerified,
}) {
final normalizedHeader = headerName.trim();
if (normalizedHeader.isEmpty) {
throw ArgumentError.value(headerName, 'headerName', 'must not be empty');
}
return (EngineContext ctx, Next next) async {
final request = parseApiKeyRequest(ctx, headerName: normalizedHeader);
if (request.malformed) return _invalidApiKey(ctx);
final rawKey = request.value;
if (rawKey == null) return next();
final authentication = await plugin.authenticate(rawKey);
final user = authentication == null
? null
: await userStore.findById(authentication.record.userId);
if (authentication == null || user == null) {
return _invalidApiKey(ctx);
}
ctx.request.setAttribute(authApiKeyAuthenticationAttribute, authentication);
ctx.request.setAttribute(
authPrincipalAttribute,
AuthPrincipal(
id: user.id,
roles: user.roles,
attributes: {
'apiKeyId': authentication.record.id,
'apiKeyScopes': authentication.record.scopes,
},
),
);
await onVerified?.call(ctx, authentication, user);
return next();
};
}