getKey method

Future<RSAPublicKey> getKey(
  1. Uri issuer,
  2. String alg,
  3. String kid, {
  4. bool forceFetch = false,
})

Fetches the OAuth public key with id kid from issuer.

Keys are cached by default to avoid unnecessary requests. You can disable the key cache by setting the datahub.enableKeyCache configuration value to false.

Implementation

Future<RSAPublicKey> getKey(Uri issuer, String alg, String kid,
    {bool forceFetch = false}) async {
  final cacheKey = CacheKey(issuer, alg, kid);
  if (_enableCache && !forceFetch && _cache.containsKey(cacheKey)) {
    return _cache[cacheKey]!;
  }

  final issuerClient = await RestClient.connect(issuer);
  try {
    final issuerBasePath = issuer.path.endsWith('/')
        ? issuer.path.substring(0, issuer.path.length - 1)
        : issuer.path;
    final openIdConfig = await issuerClient.getObject<Map<String, dynamic>>(
      '$issuerBasePath/.well-known/openid-configuration',
    )
      ..throwOnError();

    if (Uri.tryParse(openIdConfig.data['issuer'])?.host != issuer.host) {
      throw Exception('Issuer mismatch in openid-configuration.');
    }

    if (openIdConfig.data['jwks_uri'] == null) {
      throw Exception('Missing JWKS uri in openid-configuration.');
    }

    final jwksUri = Uri.parse(openIdConfig.data['jwks_uri']);
    final jwksClient = await RestClient.connect(jwksUri);
    try {
      final jwksRequest =
          await jwksClient.getObject<Map<String, dynamic>>(jwksUri.path)
            ..throwOnError();

      if (jwksRequest.data['keys'] is! List) {
        throw Exception('Invalid JWKS.');
      }

      for (final key in jwksRequest.data['keys']) {
        if (key['alg'] == alg && key['kid'] == kid) {
          if (key['n'] is String && key['e'] is String) {
            final n = _decodeBigInt(base64Decode(addBase64Padding(key['n'])));
            final e = _decodeBigInt(base64Decode(addBase64Padding(key['e'])));
            final pub = RSAPublicKey(n, e);
            if (_enableCache) {
              return _cache[cacheKey] = pub;
            } else {
              return pub;
            }
          } else {
            throw Exception('Could not find e/n properties on key.');
          }
        }
      }
    } finally {
      await jwksClient.close();
    }

    throw Exception('Key not found in JWKS.');
  } finally {
    await issuerClient.close();
  }
}