authenticate method

Future<AppleAuthSuccess> authenticate(
  1. Session session, {
  2. required String identityToken,
  3. required String authorizationCode,
  4. required bool isNativeApplePlatformSignIn,
  5. String? firstName,
  6. String? lastName,
  7. required Transaction? transaction,
})

Authenticates a user using an identityToken and authorizationCode.

If the external user ID is not yet known in the system, a new AuthUser is created for it.

Implementation

Future<AppleAuthSuccess> authenticate(
  final Session session, {
  required final String identityToken,
  required final String authorizationCode,

  /// Whether the sign-in was triggered from a native Apple platform app.
  ///
  /// Pass `false` for web sign-ins or 3rd party platforms like Android.
  required final bool isNativeApplePlatformSignIn,
  final String? firstName,
  final String? lastName,
  required final Transaction? transaction,
}) async {
  final verifiedIdentityToken = await _signInWithApple.verifyIdentityToken(
    identityToken,
    useBundleIdentifier: isNativeApplePlatformSignIn,
    nonce: null,
  );

  // TODO(https://github.com/serverpod/serverpod/issues/4105):
  // Handle the edge-case where we already know the user, but they
  // disconnected and now "registered" again, in which case we need to
  // receive and store the new refresh token.

  var appleAccount = await AppleAccount.db.findFirstRow(
    session,
    where: (final t) => t.userIdentifier.equals(
      verifiedIdentityToken.userId,
    ),
    transaction: transaction,
  );

  final createNewAccount = appleAccount == null;

  final AuthUserModel authUser = switch (createNewAccount) {
    true => await _authUsers.create(
      session,
      transaction: transaction,
    ),
    false => await _authUsers.get(
      session,
      authUserId: appleAccount!.authUserId,
    ),
  };

  if (createNewAccount) {
    final refreshToken = await _signInWithApple.exchangeAuthorizationCode(
      authorizationCode,
      useBundleIdentifier: isNativeApplePlatformSignIn,
    );

    appleAccount = await AppleAccount.db.insertRow(
      session,
      AppleAccount(
        userIdentifier: verifiedIdentityToken.userId,
        refreshToken: refreshToken.refreshToken,
        refreshTokenRequestedWithBundleIdentifier:
            isNativeApplePlatformSignIn,
        email: verifiedIdentityToken.email?.toLowerCase(),
        isEmailVerified: verifiedIdentityToken.emailVerified,
        isPrivateEmail: verifiedIdentityToken.isPrivateEmail,
        authUserId: authUser.id,
        firstName: firstName,
        lastName: lastName,
      ),
      transaction: transaction,
    );
  }

  final AppleAccountDetails details = (
    userIdentifier: appleAccount.userIdentifier,
    email: appleAccount.email,
    isVerifiedEmail: appleAccount.isEmailVerified,
    isPrivateEmail: appleAccount.isPrivateEmail,
    firstName: appleAccount.firstName,
    lastName: appleAccount.lastName,
  );

  return (
    appleAccountId: appleAccount.id!,
    authUserId: appleAccount.authUserId,
    details: details,
    newAccount: createNewAccount,
    scopes: authUser.scopes,
  );
}