authenticate static method
Implementation
static Future<Map<String, dynamic>> authenticate({
required String code,
String? callbackPath,
required String? clientId,
required String? clientSecret,
required String redirectBase,
}) async {
if (clientId == null || clientSecret == null) {
throw AuthException(message: 'GitHub OAuth is not configured');
}
final redirectUri = callbackPath != null
? '$redirectBase$callbackPath'
: '$redirectBase/api/auth/github/callback';
// 1. Exchange code for access token
final accessToken = await _exchangeCodeForToken(
code,
clientId,
clientSecret,
redirectUri,
);
// 2. Fetch user profile
final profile = await _fetchUserProfile(accessToken);
// 3. Get user email
String? email = profile['email'];
if (email == null || email.isEmpty) {
final emails = await _fetchUserEmails(accessToken);
Map<String, dynamic>? selected;
for (final entry in emails) {
if (entry is Map<String, dynamic> && entry['primary'] == true) {
selected = entry;
break;
}
}
selected ??= emails
.whereType<Map<String, dynamic>>()
.cast<Map<String, dynamic>>()
.firstWhere(
(e) => e['verified'] == true,
orElse: () => <String, dynamic>{},
);
selected = selected.isNotEmpty
? selected
: emails.whereType<Map<String, dynamic>>().isNotEmpty
? emails.whereType<Map<String, dynamic>>().first
: null;
email = selected?['email']?.toString();
if (email == null || email.isEmpty) {
throw AuthException(message: 'No usable email found for GitHub user');
}
}
return AuthProvider.formatUserData(
provider: 'github',
providerId: profile['id'].toString(),
email: email,
name: profile['name'] ?? profile['login'],
picture: profile['avatar_url'],
rawProfile: profile,
);
}