I’m having trouble with Spotify login in my Flutter project
I’m building a music app and trying to connect it with Spotify’s web API. The login flow seems to work at first but then fails with an error.
When I tap the login button, everything looks good. The Spotify login screen opens and I can type my username and password. But right after I hit the login button, I get this error message:
PlatformException(CANCELED, User canceled login, null, null)
The weird thing is that the user gets sent back to my app after this happens. I’m using FlutterWebAuth2 for the authentication process.
Has anyone run into this before? I’m not sure what’s causing it.
Here’s my authentication setup:
import 'dart:convert';
import 'dart:math';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
class MusicAuthService {
final String appId;
final String callbackUrl;
final List<String> permissions;
MusicAuthService({
required this.appId,
required this.callbackUrl,
this.permissions = const [
'user-read-playback-state',
'user-modify-playback-state',
'user-read-currently-playing',
'playlist-read-private',
'playlist-modify-public',
'user-library-read',
'user-follow-read',
'user-top-read',
],
});
Future<String> login() async {
final verifier = _createVerifier();
final challenge = _createChallenge(verifier);
final loginUrl = Uri.https('accounts.spotify.com', '/authorize', {
'client_id': appId,
'response_type': 'code',
'redirect_uri': callbackUrl,
'code_challenge_method': 'S256',
'code_challenge': challenge,
'scope': permissions.join(' '),
});
// Error happens here
final authResult = await FlutterWebAuth2.authenticate(
url: loginUrl.toString(),
callbackUrlScheme: Uri.parse(callbackUrl).scheme,
);
final resultUri = Uri.parse(authResult);
final authCode = resultUri.queryParameters['code'];
if (authCode == null) {
throw Exception("Could not get authorization code");
}
final tokenRequest = await http.post(
Uri.parse('https://accounts.spotify.com/api/token'),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: {
'client_id': appId,
'grant_type': 'authorization_code',
'code': authCode,
'redirect_uri': callbackUrl,
'code_verifier': verifier,
},
);
if (tokenRequest.statusCode != 200) {
throw Exception("Failed to get token: ${tokenRequest.body}");
}
final responseData = jsonDecode(tokenRequest.body);
final token = responseData['access_token'];
if (token == null) {
throw Exception("Token not found in response");
}
return token;
}
String _createVerifier() {
final random = Random.secure();
final codes = List<int>.generate(64, (_) => random.nextInt(256));
return base64UrlEncode(codes).replaceAll('=', '');
}
String _createChallenge(String verifier) {
final encoded = utf8.encode(verifier);
final hashed = sha256.convert(encoded);
return base64UrlEncode(hashed.bytes).replaceAll('=', '');
}
}
And here’s how I use it in my main app:
import 'package:flutter/material.dart';
void main() {
runApp(MusicApp());
}
class MusicApp extends StatelessWidget {
final MusicAuthService authService = MusicAuthService(
appId: '****YOUR_APP_ID****',
callbackUrl: 'myspotifyapp://auth',
);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Music Player')),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
final accessToken = await authService.login();
print('Got token: $accessToken');
} catch (e) {
print('Login failed: $e');
}
},
child: Text('Connect Spotify Account'),
),
),
),
);
}
}
I’ve checked my Spotify app settings multiple times and the redirect URL matches what I have in the code. Any ideas what might be wrong?