import 'package:graphql/client.dart'; import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:shopping_assistant_mobile_client/constants/jwt_claims.dart'; import 'package:uuid/uuid.dart'; class AuthenticationService { final GraphQLClient client = GraphQLClient( cache: GraphQLCache(), link: HttpLink('https://shopping-assistant-api-dev.azurewebsites.net/graphql'), ); late SharedPreferences prefs; Future getAccessToken() async { prefs = await SharedPreferences.getInstance(); var accessToken = prefs.getString('accessToken'); var refreshToken = prefs.getString('refreshToken'); if (accessToken == null && refreshToken != null) { print('WTF??'); } else if (accessToken == null && refreshToken == null) { accessToken = await _accessGuest(); print('Got new access token $accessToken'); } else if (JwtDecoder.isExpired(accessToken!)) { accessToken = await _refreshAccessToken(); print('Refreshed access token $accessToken'); } print('Returned access token $accessToken'); return accessToken!; } Future login(String? email, String? phone, String password) async { prefs = await SharedPreferences.getInstance(); const String loginQuery = r''' mutation Login($login: AccessUserModelInput!) { login(login: $login) { accessToken refreshToken } } '''; final MutationOptions options = MutationOptions( document: gql(loginQuery), variables: { 'login': { 'email': email, 'phone': phone, 'password': password, }, }, ); final QueryResult result = await client.mutate(options); if (result.hasException) { print(result.exception.toString()); } final accessToken = result.data?['login']['accessToken'] as String; final refreshToken = result.data?['login']['refreshToken'] as String; prefs.setString('accessToken', accessToken); prefs.setString('refreshToken', refreshToken); } Future _accessGuest() async { prefs = await SharedPreferences.getInstance(); String? guestId = prefs.getString('guestId'); guestId ??= const Uuid().v4(); prefs.setString('guestId', guestId); const String accessGuestMutation = r''' mutation AccessGuest($guest: AccessGuestModelInput!) { accessGuest(guest: $guest) { accessToken refreshToken } } '''; final MutationOptions options = MutationOptions( document: gql(accessGuestMutation), variables: { 'guest': {'guestId': guestId}, }, ); final QueryResult result = await client.mutate(options); if (result.hasException) { print(result.exception.toString()); } final String accessToken = result.data?['accessGuest']['accessToken'] as String; final String refreshToken = result.data?['accessGuest']['refreshToken'] as String; prefs.setString('accessToken', accessToken); prefs.setString('refreshToken', refreshToken); return accessToken; } Future _refreshAccessToken() async { var accessToken = prefs.getString('accessToken'); var refreshToken = prefs.getString('refreshToken'); const String refreshAccessTokenMutation = r''' mutation RefreshAccessToken($model: TokensModelInput!) { refreshAccessToken(model: $model) { accessToken refreshToken } } '''; final QueryOptions options = QueryOptions( document: gql(refreshAccessTokenMutation), variables: { 'model': { 'accessToken': accessToken, 'refreshToken': refreshToken, }, }, ); final QueryResult result = await client.query(options); if (result.hasException) { print(result.exception.toString()); } accessToken = result.data?['refreshAccessToken']['accessToken'] as String; refreshToken = result.data?['refreshAccessToken']['refreshToken'] as String; prefs.setString('accessToken', accessToken); prefs.setString('refreshToken', refreshToken); return accessToken; } String getIdFromAccessToken(String accessToken) { var decodedToken = JwtDecoder.decode(accessToken); return decodedToken[JwtClaims.id]; } String getEmailFromAccessToken(String accessToken) { var decodedToken = JwtDecoder.decode(accessToken); return decodedToken[JwtClaims.email]; } String getPhoneFromAccessToken(String accessToken) { var decodedToken = JwtDecoder.decode(accessToken); return decodedToken[JwtClaims.phone]; } // List getRolesFromAccessToken(String accessToken) { // var decodedToken = JwtDecoder.decode(accessToken); // List roles = []; // for (var role in decodedToken[JwtClaims.roles] as List) { // roles.add(role); // } // return roles; // } }