Add login/logout, streamline token logic

This commit is contained in:
Tommy Chow 2021-08-25 00:43:51 -04:00
parent 3dcba65b79
commit cd6f998a1a

View file

@ -4,8 +4,11 @@ import 'package:frosty/constants.dart';
import 'package:frosty/models/user.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_web_auth/flutter_web_auth.dart';
class Authentication extends ChangeNotifier {
// TODO: Fix up notifyListeners() placements.
class AuthenticationProvider extends ChangeNotifier {
final _storage = new FlutterSecureStorage();
final _secret = const String.fromEnvironment('SECRET');
final _clientId = const String.fromEnvironment('CLIENT_ID');
@ -19,17 +22,32 @@ class Authentication extends ChangeNotifier {
/// Initialize by retrieving a token if it does not already exist.
Future<void> init() async {
debugPrint('Creating auth provider');
token = await _storage.read(key: 'USER_TOKEN') ?? await getDefaultToken();
// Read and set the currently stored user token, if any.
token = await _storage.read(key: 'USER_TOKEN');
// If the token does not exist, get the default token.
// Otherwise, log in and get the user info.
if (token != null) {
isLoggedIn = true;
authHeaders = {'Authorization': 'Bearer $token', 'Client-Id': _clientId};
await getUserInfo();
} else {
await getDefaultToken();
}
// Set the auth headers for future requests and validate the token.
authHeaders = {'Authorization': 'Bearer $token', 'Client-Id': _clientId};
if (isLoggedIn) await getUserInfo();
notifyListeners();
await validateToken();
debugPrint('Created auth provider');
}
/// Returns a token for an anonymous user.
Future<String> getDefaultToken() async {
Future<void> getDefaultToken() async {
debugPrint('Getting default token...');
token = await _storage.read(key: 'DEFAULT_TOKEN');
if (token != null) return;
final url = Uri(
scheme: 'https',
host: 'id.twitch.tv',
@ -42,32 +60,73 @@ class Authentication extends ChangeNotifier {
);
final response = await http.post(url);
final token = jsonDecode(response.body)['access_token'];
_storage.write(key: 'USER_TOKEN', value: token);
final defaultToken = jsonDecode(response.body)['access_token'];
return token;
await _storage.write(key: 'DEFAULT_TOKEN', value: defaultToken);
token = defaultToken;
}
Future<void> validateToken() async {
debugPrint('Validating token...');
final response = await http.get(Uri.parse(twitchValidateUrl), headers: {'Authorization': 'Bearer $token'});
if (response.statusCode == 200) {
debugPrint('Token validated!');
tokenIsValid = true;
notifyListeners();
return;
}
print('Token invalidated');
debugPrint('Token invalidated :(');
tokenIsValid = false;
notifyListeners();
}
Future<UserTwitch> getUserInfo() async {
Future<void> getUserInfo() async {
final response = await http.get(Uri.parse(twitchUsersUrl), headers: authHeaders);
final userData = jsonDecode(response.body)['data'];
final userData = jsonDecode(response.body)['data'] as List;
return UserTwitch.fromJson(userData);
user = UserTwitch.fromJson(userData.first);
}
Future<void> login() async {
final loginUrl = Uri(
scheme: 'https',
host: 'id.twitch.tv',
path: '/oauth2/authorize',
queryParameters: {
'client_id': _clientId,
'redirect_uri': 'auth://',
'response_type': 'token',
'scope': 'chat:read chat:edit user:read:follows',
},
);
try {
final result = await FlutterWebAuth.authenticate(url: loginUrl.toString(), callbackUrlScheme: 'auth');
final fragment = Uri.parse(result).fragment;
token = fragment.substring(fragment.indexOf('=') + 1, fragment.indexOf('&'));
await _storage.write(key: 'USER_TOKEN', value: token);
isLoggedIn = true;
authHeaders = {'Authorization': 'Bearer $token', 'Client-Id': _clientId};
await getUserInfo();
notifyListeners();
} catch (error) {
debugPrint('Login failed due to $error');
}
}
void logout() async {
await getDefaultToken();
isLoggedIn = false;
await _storage.delete(key: 'USER_TOKEN');
debugPrint('Succesfully logged out');
notifyListeners();
}
}