authenticate method

Future<void> authenticate(
  1. String clientId,
  2. String redirectUri, [
  3. List<String>? scopes
])

Implementation

Future<void> authenticate(String clientId, String redirectUri, [List<String>? scopes]) async {
  if (await tryRestoreToken()) return;

  final codeVerifier = _generateCodeVerifier();
  final codeChallenge = _codeChallenge(codeVerifier);

  final authUri = Uri.https('accounts.spotify.com', '/authorize', {
    'client_id': clientId,
    'response_type': 'code',
    'redirect_uri': redirectUri,
    'code_challenge_method': 'S256',
    'code_challenge': codeChallenge,
    'scope': scopes?.join(' '),
  });

  final completer = Completer<String>();
  _sub = uriLinkStream.listen((Uri? uri) {
    if (uri != null && uri.toString().startsWith(redirectUri)) {
      final code = uri.queryParameters['code'];
      code != null
          ? completer.complete(code)
          : completer.completeError('Authorization code missing');
      _sub?.cancel();
    }
  });

  if (!await launchUrl(authUri, mode: LaunchMode.externalApplication)) {
    _sub?.cancel();
    throw Exception("Coould not open authorization URL");
  }

  final code = await completer.future;

  final response = await http.post(
    Uri.parse('https://accounts.spotify.com/api/token'),
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: {
      'client_id': clientId,
      'grant_type': 'authorization_code',
      'code': code,
      'redirect_uri': redirectUri,
      'code_verifier': codeVerifier,
    },
  );

  if (response.statusCode != 200) {
    throw Exception("Token exchange failed: ${response.body}");
  }

  final jsonBody = jsonDecode(response.body);
  jsonBody['client_id'] = clientId;
  await _saveTokenData(jsonBody);
  _accessToken = jsonBody['access_token'];
}