ios build, connected data (not finished)

This commit is contained in:
2025-11-14 12:27:40 -05:00
parent 4b03e9aba5
commit ccb817e3c6
81 changed files with 3127 additions and 284 deletions
+93 -25
View File
@@ -1,46 +1,114 @@
import 'package:flutter_appauth/flutter_appauth.dart';
import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart' as http;
import 'package:http_interceptor/http_interceptor.dart';
import 'package:jwt_decoder/jwt_decoder.dart';
import '../models/user_profile.dart';
import '../utils/logging_interceptor.dart';
class AuthService {
static const String _tokenKey = 'auth_token';
static const String _refreshTokenKey = 'refresh_token';
static const String _tokenEndpoint = 'https://auth.goutezplanb.com/realms/planb-internal/protocol/openid-connect/token';
static const String _clientId = 'delivery-mobile-app';
final FlutterAppAuth _appAuth;
final FlutterSecureStorage _secureStorage;
final http.Client _httpClient;
AuthService({
FlutterAppAuth? appAuth,
FlutterSecureStorage? secureStorage,
}) : _appAuth = appAuth ?? const FlutterAppAuth(),
_secureStorage = secureStorage ?? const FlutterSecureStorage();
Future<AuthResult> login() async {
try {
final result = await _appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
'delivery-mobile-app',
'com.goutezplanb.delivery://callback',
discoveryUrl: 'https://auth.goutezplanb.com/realms/planb-internal/.well-known/openid-configuration',
scopes: const ['openid', 'profile', 'offline_access'],
promptValues: const ['login'],
http.Client? httpClient,
}) : _secureStorage = secureStorage ?? const FlutterSecureStorage(
aOptions: AndroidOptions(
encryptedSharedPreferences: true,
),
iOptions: IOSOptions(
accessibility: KeychainAccessibility.first_unlock,
),
mOptions: MacOsOptions(
accessibility: KeychainAccessibility.first_unlock,
),
),
_httpClient = httpClient ?? InterceptedClient.build(
interceptors: [LoggingInterceptor()],
);
Future<AuthResult> login({
required String username,
required String password,
}) async {
try {
final response = await _httpClient.post(
Uri.parse(_tokenEndpoint),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'grant_type': 'password',
'client_id': _clientId,
'username': username,
'password': password,
'scope': 'openid profile offline_access',
},
);
// ignore: unnecessary_null_comparison
if (result == null) {
return const AuthResult.cancelled();
}
if (response.statusCode == 200) {
final data = json.decode(response.body) as Map<String, dynamic>;
final accessToken = data['access_token'] as String;
final refreshToken = data['refresh_token'] as String?;
await _secureStorage.write(key: _tokenKey, value: result.accessToken ?? '');
if (result.refreshToken != null) {
await _secureStorage.write(key: _refreshTokenKey, value: result.refreshToken!);
}
await _secureStorage.write(key: _tokenKey, value: accessToken);
if (refreshToken != null) {
await _secureStorage.write(key: _refreshTokenKey, value: refreshToken);
}
return AuthResult.success(token: result.accessToken ?? '');
return AuthResult.success(token: accessToken);
} else if (response.statusCode == 401) {
return AuthResult.error(error: 'Invalid username or password');
} else {
return AuthResult.error(error: 'Authentication failed: ${response.statusCode}');
}
} catch (e) {
return AuthResult.error(error: e.toString());
return AuthResult.error(error: 'Network error: ${e.toString()}');
}
}
Future<AuthResult> refreshAccessToken() async {
try {
final refreshToken = await getRefreshToken();
if (refreshToken == null) {
return AuthResult.error(error: 'No refresh token available');
}
final response = await _httpClient.post(
Uri.parse(_tokenEndpoint),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: {
'grant_type': 'refresh_token',
'client_id': _clientId,
'refresh_token': refreshToken,
},
);
if (response.statusCode == 200) {
final data = json.decode(response.body) as Map<String, dynamic>;
final accessToken = data['access_token'] as String;
final newRefreshToken = data['refresh_token'] as String?;
await _secureStorage.write(key: _tokenKey, value: accessToken);
if (newRefreshToken != null) {
await _secureStorage.write(key: _refreshTokenKey, value: newRefreshToken);
}
return AuthResult.success(token: accessToken);
} else {
await logout();
return AuthResult.error(error: 'Token refresh failed');
}
} catch (e) {
return AuthResult.error(error: 'Token refresh error: ${e.toString()}');
}
}