import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:logging/logging.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:shared_models/jwt.dart'; import 'package:shared_preferences/shared_preferences.dart'; part 'auth.g.dart'; final logger = Logger('provider/auth'); @riverpod class JwtNotifier extends _$JwtNotifier { @override Future<String?> build() async { if (!await SharedPreferencesAsync().containsKey('jwt')) { logger.fine('No JWT saved to client'); return null; } final jwtString = await SharedPreferencesAsync().getString('jwt'); if (jwtString == null) { logger.fine('Saved JWT came back null, removing key'); SharedPreferencesAsync().remove('jwt'); return null; } return jwtString; } Future<void> setJwt(String jwt) async { final payload = JwtDecoder.tryDecode(jwt); if (payload == null) { logger.info('Tried to set JWT token that did not decode to payload'); state = AsyncValue.error('JWT set to invalid token', StackTrace.current); return; } logger.fine('Saving jwt token to shared prefs'); await SharedPreferencesAsync().setString('jwt', jwt); state = AsyncValue.data(jwt); } Future<void> eraseJwt() async { SharedPreferencesAsync().remove('jwt'); state = AsyncValue.data(null); } } @riverpod JWTBody? jwtBody(Ref ref) { final jwtString = ref.watch(jwtNotifierProvider).valueOrNull; if (jwtString == null) { return null; } final payload = JwtDecoder.tryDecode(jwtString); if (payload == null) { logger.fine('Failed to decode JWT, removing key.'); Future.delayed(const Duration(), () => ref.read(jwtNotifierProvider.notifier).eraseJwt()); return null; } try { final body = JWTBody.fromJson(payload); return body; } catch (e) { logger.shout( 'Failed to parse JWT payload to JWTBody, something is wrong.\nPayload: $payload', e, StackTrace.current); Future.delayed(const Duration(), () => ref.read(jwtNotifierProvider.notifier).eraseJwt()); return null; } }