Flutter Spotify authentication returns CANCELLED error after successful login

I’m building a Flutter app that integrates with Spotify’s authentication system. Everything seems to work fine during the login process, but after I successfully enter my credentials and get redirected back to my app, I keep getting a CANCELLED error message saying the user cancelled the login, even though I didn’t cancel anything.

Here’s my authentication service code:

class SpotifyAuthService {
  static const appId = '//your-app-id';
  static const appSecret = '//your-app-secret';
  static const callbackUrl = 'myapp://auth';

  static const String loginEndpoint = 'https://accounts.spotify.com/authorize';
  static const String accessTokenEndpoint = 'https://accounts.spotify.com/api/token';
  static const String profileEndpoint = 'https://api.spotify.com/v1/me';

  static Future<String?> performAuth() async {
    final loginUrlWithQuery =
        '$loginEndpoint?response_type=code&client_id=$appId&scope=user-read-private user-read-email&redirect_uri=$callbackUrl';

    try {
      final authResult = await FlutterWebAuth.authenticate(
          url: loginUrlWithQuery, callbackUrlScheme: 'myapp');

      final authCode = Uri.parse(authResult).queryParameters['code'];

      if (authCode != null) {
        return await _getAccessToken(authCode);
      } else {
         return null;
      }
    } catch (error) {
      if (error.toString().contains('CANCELLED')) {
         print('User cancelled the authentication process.');
        return null;
      } else {
        print('Authentication error occurred: $error');
        return null;
      }
    }
  }

  static Future<String?> _getAccessToken(String authCode) async {
    try {
      final httpClient = Dio();
      final tokenResponse = await httpClient.post(
        accessTokenEndpoint,
        data: {
          'grant_type': 'authorization_code',
          'code': authCode,
          'redirect_uri': callbackUrl,
        },
        options: Options(
          headers: {
            'Authorization': 'Basic ' + base64Encode(utf8.encode('$appId:$appSecret')),
          },
        ),
      );

      if (tokenResponse.statusCode == 200) {
        return tokenResponse.data['access_token'];
      } else {
        print('Failed to get access token: ${tokenResponse.statusCode}');
        return null;
      }
    } catch (error) {
      print('Token exchange error: $error');
      return null;
    }
  }

  static Future<Map<String, dynamic>?> fetchUserData(String accessToken) async {
    // implementation here
  }
}

After successful authentication, I want to navigate to my main screen and display user information. Has anyone experienced this issue before?

i had the same issue too a while ago. just make sure your app is registered correctly in the spotify dev console with the exact callback URL. And also, check that your app is set up to handle deep links in the AndroidManifest.xml or iOS plist files. that cancelled error usually shows up when the redirect fails.

Sounds like a webview lifecycle issue. Add a state parameter to your auth URL and make sure your activity doesn’t get destroyed during the redirect. Also check that myapp://auth is set up correctly in your URL schemes - sometimes auth works but the callback never makes it back.

The CANCELLED error usually happens when your callback URL scheme doesn’t match what FlutterWebAuth expects. I’ve hit this before - it’s almost always a config issue. Check your AndroidManifest.xml intent filters first. The scheme needs to match exactly what you’re passing to callbackUrlScheme. Also make sure your Spotify app uses the same redirect URI format. Sometimes you’ll get this error even when auth actually works - happens when the webview gets killed too fast. Wrap your FlutterWebAuth.authenticate call in a try-catch for PlatformException and check the error code. For me, adding a proper state parameter and preventing the activity from recreating during auth fixed it.

This happens when FlutterWebAuth gets an incomplete or broken callback URL. Usually it’s a timing issue - the auth window closes before the callback gets processed properly. I ran into this same problem and adding a small delay after the redirect fixed it. Also check if your app’s getting killed or backgrounded during the redirect. Another thing - make sure you don’t have multiple auth flows running at once. Add some debug logging to see what authResult actually contains before you try parsing it. Sometimes the callback URL is missing parameters even when Spotify says auth was successful.