login method

Future<AuthSuccess> login(
  1. Session session, {
  2. required String code,
  3. required String codeVerifier,
  4. required String redirectUri,
  5. required bool isWebPlatform,
  6. Transaction? transaction,
})

Validates a Microsoft authorization code and either logs in the associated user or creates a new user account if the Microsoft account ID is not yet known.

This method exchanges the authorization code for an access token using PKCE, then authenticates the user.

The isWebPlatform flag indicates whether the client is a web application. Microsoft requires the client secret only for confidential clients (web apps). Public clients (mobile, desktop) using PKCE must not include it. Pass true for web clients and false for native platforms.

If a new user is created an associated UserProfile is also created.

Implementation

Future<AuthSuccess> login(
  final Session session, {
  required final String code,
  required final String codeVerifier,
  required final String redirectUri,
  required final bool isWebPlatform,
  final Transaction? transaction,
}) async {
  return await DatabaseUtil.runInTransactionOrSavepoint(
    session.db,
    transaction,
    (final transaction) async {
      final accessToken = await utils.exchangeCodeForToken(
        session,
        code: code,
        codeVerifier: codeVerifier,
        redirectUri: redirectUri,
        isWebPlatform: isWebPlatform,
      );

      final account = await utils.authenticate(
        session,
        accessToken: accessToken,
        transaction: transaction,
      );

      final imageBytes = account.details.imageBytes;
      if (account.newAccount) {
        try {
          await _userProfiles.createUserProfile(
            session,
            account.authUserId,
            UserProfileData(
              fullName: account.details.name?.trim(),
              email: account.details.email,
            ),
            transaction: transaction,
            imageSource: imageBytes != null
                ? UserImageFromBytes(imageBytes)
                : null,
          );
        } catch (e, stackTrace) {
          session.log(
            'Failed to create user profile for new Microsoft user.',
            level: LogLevel.error,
            exception: e,
            stackTrace: stackTrace,
          );
        }
      } else if (imageBytes != null) {
        try {
          final user = await UserProfile.db.findFirstRow(
            session,
            where: (final t) => t.authUserId.equals(account.authUserId),
            transaction: transaction,
          );
          if (user != null && user.image == null) {
            await _userProfiles.setUserImageFromBytes(
              session,
              account.authUserId,
              imageBytes,
              transaction: transaction,
            );
          }
        } catch (e, stackTrace) {
          session.log(
            'Failed to update user profile image for existing Microsoft user.',
            level: LogLevel.error,
            exception: e,
            stackTrace: stackTrace,
          );
        }
      }

      return _tokenIssuer.issueToken(
        session,
        authUserId: account.authUserId,
        transaction: transaction,
        method: method,
        scopes: account.scopes,
      );
    },
  );
}