resolveOAuthSignInForProvider<TContext, TProfile extends Object> function
Future<AuthOAuthSignInResolution>
resolveOAuthSignInForProvider<TContext, TProfile extends Object>({})
Resolves OAuth callback payloads into user/account/profile sign-in data.
Implementation
Future<AuthOAuthSignInResolution>
resolveOAuthSignInForProvider<TContext, TProfile extends Object>({
required AuthStore store,
required TContext context,
required OAuthProvider<TProfile> provider,
required String code,
required http.Client httpClient,
String? codeVerifier,
String? oidcNonce,
String Function()? fallbackAccountId,
}) async {
late OAuthTokenResponse tokenResponse;
try {
tokenResponse = await exchangeOAuthAuthorizationCode(
provider,
code: code,
codeVerifier: codeVerifier,
httpClient: httpClient,
);
} catch (_) {
throw AuthFlowException('token_exchange_failed');
}
final rawProfile = await loadOAuthProfile(
provider,
token: tokenResponse,
httpClient: httpClient,
oidcNonce: oidcNonce,
);
late final TProfile enrichedProfile;
late final AuthUser user;
late final Map<String, dynamic> profileMap;
try {
final parsedProfile = provider.parseProfile(rawProfile);
enrichedProfile = await Future.sync(
() => provider.enrichProfile(
context,
tokenResponse,
httpClient,
parsedProfile,
),
);
final mappedUser = provider.mapProfile(enrichedProfile);
final overrideUser = await Future.sync(
() => provider.overrideProfile(context, enrichedProfile),
);
user = overrideUser ?? mappedUser;
profileMap = provider.serializeProfile(enrichedProfile);
} on AuthFlowException {
rethrow;
} catch (_) {
throw AuthFlowException('profile_invalid');
}
final emailVerified =
profileMap['verified'] == true || profileMap['email_verified'] == true;
final accountId = resolveAuthAccountId(
profileMap,
user,
fallbackId: fallbackAccountId ?? secureRandomToken,
emailVerified: emailVerified,
);
final accountExpiresAt = oauthTokenExpiryFromSeconds(tokenResponse.expiresIn);
final userResolution = await resolveOAuthUserForAccount(
store: store,
providerId: provider.id,
accountId: accountId,
mappedUser: user,
// Only link to a local account by email when the provider asserted
// ownership of the address (Discord `verified`, Google `email_verified`,
// GitHub `verified`, ...). Unverified profile emails must never take over
// an existing local user.
emailVerified: emailVerified,
);
final account = buildOAuthAuthAccount(
providerId: provider.id,
providerAccountId: accountId,
userId: userResolution.user.id,
token: tokenResponse,
expiresAt: accountExpiresAt,
metadata: profileMap,
);
await linkOAuthAccountOrThrow(store: store, account: account);
return AuthOAuthSignInResolution(
user: userResolution.user,
isNewUser: userResolution.isNewUser,
userUpdated: userResolution.userUpdated,
account: account,
profile: profileMap,
);
}