complete method

Future<OAuthGrant> complete(
  1. PendingAuthorization pending,
  2. Uri redirect
)

The second half: judge the redirect the authorization server sent back and redeem its code. The issuer is checked first, then state; an error is reported only once both hold.

Implementation

Future<OAuthGrant> complete(PendingAuthorization pending, Uri redirect) async {
  final params = redirect.queryParameters;
  checkAuthorizationResponseIssuer(
    recordedIssuer: pending.issuer,
    issParameterSupported: pending.issParameterSupported,
    iss: params['iss'],
  );
  if (params['state'] != pending.state) {
    throw const OAuthError(
        error: 'invalid_state', errorDescription: 'The answer is not for the request this client made');
  }
  final error = params['error'];
  if (error != null) {
    throw OAuthError(error: error, errorDescription: params['error_description'], errorUri: params['error_uri']);
  }
  final code = params['code'];
  if (code == null) {
    throw const OAuthError(error: 'invalid_request', errorDescription: 'The answer carries no code');
  }
  final registration = await _knownRegistration(pending.issuer, pending.clientId);
  final token = await _tokenRequest(pending.tokenEndpoint, registration, {
    'grant_type': 'authorization_code',
    'code': code,
    'redirect_uri': pending.redirectUri,
    'code_verifier': pending.codeVerifier,
    'resource': pending.resource,
  });
  final grant = OAuthGrant(
    issuer: pending.issuer,
    resource: pending.resource,
    tokenEndpoint: pending.tokenEndpoint,
    clientId: pending.clientId,
    token: token,
    scopes: token.scopes ?? pending.scopes,
  );
  await options.store.saveGrant(grant);
  return grant;
}