check method
Checks presented, with the reason when it does not authenticate.
tenant is the tenant the request resolved to. When it is not given
and the call runs inside a DV.Tenants.withTenant scope, that scope's
tenant is the one the key must belong to.
Implementation
Future<DVApiKeyCheck> check(String presented, {String? tenant}) async {
final String? id = _idOf(presented);
if (id == null) {
return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
}
final DVRecord? record = await _keys.read(id);
if (record == null) {
DVSecretHash.matches(_absentHash, presented);
return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
}
if (!DVSecretHash.matches('${record.values['secret_hash']}', presented)) {
return const DVApiKeyCheck.failed(DVApiKeyFailure.invalid);
}
final DVApiKey key = _keyFrom(record);
final DateTime now = _now();
if (key.revokedAt != null) {
return DVApiKeyCheck.failed(DVApiKeyFailure.revoked, key: key);
}
final DateTime? expiry = key.expiresAt;
if (expiry != null && !now.isBefore(expiry)) {
if (key.rotatedTo == null) {
return DVApiKeyCheck.failed(DVApiKeyFailure.expired, key: key);
}
_log.info(
'DV-APIKEY-003: rotation overlap expired; ${key.prefix} no longer '
'authenticates, its replacement is ${keyPrefix}${key.rotatedTo}.',
);
return DVApiKeyCheck.failed(
DVApiKeyFailure.expired,
key: key,
code: 'DV-APIKEY-003',
);
}
final String? requested =
tenant ?? (DVTenants.hasScope ? const DVTenants().currentTenant : null);
if (requested != null && requested != key.tenant) {
return DVApiKeyCheck.failed(DVApiKeyFailure.wrongTenant, key: key);
}
return DVApiKeyCheck.valid(key, principalFor(key));
}