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?