exchangeCodeForToken method

  1. @override
Future<OAuthToken> exchangeCodeForToken({
  1. required String code,
  2. required String codeVerifier,
})
override

Exchange authorization code for token

Implementation

@override
Future<OAuthToken> exchangeCodeForToken({
  required String code,
  required String codeVerifier,
}) async {
  final metadata = await _discoverMetadata();

  final body = <String, String>{
    'grant_type': 'authorization_code',
    'code': code,
    'client_id': config.clientId,
    'code_verifier': codeVerifier,
    if (config.redirectUri != null) 'redirect_uri': config.redirectUri!,
  };

  final headers = <String, String>{
    'Content-Type': 'application/x-www-form-urlencoded',
    'Accept': 'application/json',
  };

  // Add client authentication if confidential client
  if (config.clientSecret != null) {
    final credentials = base64Encode(
      utf8.encode('${config.clientId}:${config.clientSecret}'),
    );
    headers['Authorization'] = 'Basic $credentials';
  }

  final response = await _httpClient.post(
    Uri.parse(metadata.tokenEndpoint),
    headers: headers,
    body: body.entries
        .map((e) => '${e.key}=${Uri.encodeComponent(e.value)}')
        .join('&'),
  );

  final json = jsonDecode(response.body) as Map<String, dynamic>;

  if (response.statusCode != 200) {
    throw OAuthError.fromJson(json);
  }

  return OAuthToken.fromJson(json);
}