Menambahkan autentikasi multi-faktor TOTP ke aplikasi iOS

Jika telah mengupgrade ke Firebase Authentication dengan Identity Platform, Anda dapat menambahkan autentikasi multi-faktor (MFA) sandi sekali pakai (MTP) berbasis waktu ke aplikasi Anda.

Firebase Authentication dengan Identity Platform memungkinkan Anda menggunakan TOTP sebagai faktor tambahan untuk MFA. Jika Anda mengaktifkan fitur ini, pengguna yang mencoba login ke aplikasi Anda akan melihat permintaan TOTP. Untuk membuatnya, mereka harus menggunakan aplikasi pengautentikasi yang mampu menghasilkan kode TOTP yang valid, seperti Google Authenticator.

Sebelum memulai

  1. Aktifkan minimal satu penyedia yang mendukung MFA. Perhatikan bahwa semua penyedia kecuali penyedia berikut mendukung MFA:

    • Autentikasi ponsel
    • Autentikasi anonim
    • Token autentikasi kustom
    • Apple Game Center
  2. Pastikan aplikasi Anda memverifikasi alamat email pengguna. MFA memerlukan verifikasi email. Tindakan ini mencegah pelaku kejahatan mendaftar ke layanan dengan alamat email yang bukan miliknya, lalu mengunci pemilik alamat email yang sebenarnya dengan menambahkan faktor kedua.

  3. Jika Anda belum melakukannya, instal Firebase Apple SDK.

    TOTP MFA hanya didukung di Apple SDK versi v10.12.0 dan yang lebih baru, dan hanya di iOS.

Mengaktifkan TOTP MFA

Untuk mengaktifkan TOTP sebagai faktor kedua, gunakan Admin SDK atau panggil endpoint REST konfigurasi project.

Untuk menggunakan Admin SDK, jalankan berikut ini:

  1. Jika Anda belum melakukannya, instal Firebase Admin Node.js SDK.

    TOTP MFA hanya didukung di Firebase Admin Node.js SDK versi 11.6.0 dan yang lebih baru.

  2. Jalankan perintah berikut:

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: {
                          NUM_ADJ_INTERVALS
                      },
                  }
              }]
          }
    })
    

    Ganti kode berikut:

    • NUM_ADJ_INTERVALS: Jumlah interval jangka waktu yang berdekatan yang digunakan untuk menerima TOTP, dari nol hingga sepuluh. Jumlah defaultnya adalah lima.

      TOTP bekerja dengan memastikan bahwa jika dua pihak (prover dan validator) membuat OTP dalam jangka waktu yang sama (biasanya berdurasi 30 detik), keduanya menghasilkan sandi yang sama. Namun, untuk mengakomodasi selisih waktu di antara kedua pihak dan waktu respons manusia, Anda dapat mengonfigurasi layanan TOTP agar juga menerima TOTP dari jangka waktu yang berdekatan.

Untuk mengaktifkan TOTP MFA menggunakan REST API, jalankan perintah berikut:

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": "NUM_ADJ_INTERVALS"
            }
          }]
       }
    }'

Ganti kode berikut:

  • PROJECT_ID: Project ID.
  • NUM_ADJ_INTERVALS: Jumlah interval jangka waktu, dari nol hingga sepuluh. Jumlah defaultnya adalah lima.

    TOTP bekerja dengan memastikan bahwa jika dua pihak (prover dan validator) membuat OTP dalam jangka waktu yang sama (biasanya berdurasi 30 detik), keduanya menghasilkan sandi yang sama. Namun, untuk mengakomodasi selisih waktu di antara kedua pihak dan waktu respons manusia, Anda dapat mengonfigurasi layanan TOTP agar juga menerima TOTP dari jangka waktu yang berdekatan.

Memilih pola pendaftaran

Anda dapat memilih apakah aplikasi memerlukan autentikasi multi-faktor atau tidak, serta cara dan waktu untuk mendaftarkan pengguna. Beberapa pola yang umum antara lain:

  • Mendaftarkan faktor kedua pengguna sebagai bagian dari pendaftaran. Gunakan metode ini jika aplikasi Anda memerlukan autentikasi multi-faktor untuk semua pengguna.

  • Menawarkan opsi yang dapat dilewati untuk mendaftarkan faktor kedua selama pendaftaran. Jika Anda ingin mendukung, tetapi tidak memerlukan autentikasi multi-faktor di aplikasi, Anda dapat menggunakan pendekatan ini.

  • Memungkinkan untuk menambahkan faktor kedua dari halaman pengelolaan akun atau profil pengguna, bukan dari layar pendaftaran. Hal ini akan meminimalkan hambatan selama proses pendaftaran, sekaligus tetap menyediakan autentikasi multi-faktor untuk pengguna yang rentan terhadap ancaman keamanan.

  • Memerlukan penambahan faktor kedua secara inkremental saat pengguna ingin mengakses fitur dengan persyaratan keamanan yang ditingkatkan.

Mendaftarkan pengguna di TOTP MFA

Setelah Anda mengaktifkan TOTP MFA sebagai faktor kedua untuk aplikasi Anda, terapkan logika sisi klien untuk mendaftarkan pengguna di TOTP MFA:

  1. Autentikasi ulang pengguna.

  2. Buat rahasia TOTP untuk pengguna terautentikasi:

    // Generate a TOTP secret.
    guard let mfaSession = try? await currentUser.multiFactor.session() else { return }
    guard let totpSecret = try? await TOTPMultiFactorGenerator.generateSecret(with: mfaSession) else { return }
    
    // Display the secret to the user and prompt them to enter it into their
    // authenticator app. (See the next step.)
    
  3. Tampilkan rahasia kepada pengguna dan minta mereka memasukkannya ke dalam aplikasi pengautentikasi mereka:

    // Display this key:
    let secret = totpSecret.sharedSecretKey()
    

    Selain menampilkan kunci rahasia, Anda dapat mencoba menambahkannya secara otomatis ke aplikasi pengautentikasi default perangkat. Untuk melakukannya, buat URI kunci yang kompatibel dengan Google Authenticator, dan teruskan ke openInOTPApp(withQRCodeURL:):

    let otpAuthUri = totpSecret.generateQRCodeURL(
        withAccountName: currentUser.email ?? "default account",
        issuer: "Your App Name")
    totpSecret.openInOTPApp(withQRCodeURL: otpAuthUri)
    

    Setelah pengguna menambahkan rahasia ke aplikasi pengautentikasinya, rahasia tersebut akan mulai menghasilkan TOTP.

  4. Minta pengguna mengetik TOTP yang ditampilkan di aplikasi pengautentikasi mereka dan menggunakannya untuk menyelesaikan pendaftaran MFA:

    // Ask the user for a verification code from the authenticator app.
    let verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    let multiFactorAssertion = TOTPMultiFactorGenerator.assertionForEnrollment(
        with: totpSecret,
        oneTimePassword: verificationCode)
    do {
        try await currentUser.multiFactor.enroll(
            with: multiFactorAssertion,
            displayName: "TOTP")
    } catch {
        // Wrong or expired OTP. Re-prompt the user.
    }
    

Memproses login pengguna dengan faktor kedua

Untuk memproses login pengguna dengan TOTP MFA, gunakan kode berikut:

  1. Panggil salah satu metode signIn(with...:) seperti yang Anda lakukan jika tidak menggunakan MFA (misalnya, signIn(withEmail:password:)). Jika metode tersebut menampilkan error dengan kode secondFactorRequired, mulai alur MFA aplikasi Anda.

    do {
        let authResult = try await Auth.auth().signIn(withEmail: email, password: password)
    
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch let error as AuthErrorCode where error.code == .secondFactorRequired {
        // Initiate your second factor sign-in flow. (See next step.)
        // ...
    } catch {
        // Other auth error.
        throw error
    }
    
  2. Alur MFA aplikasi Anda harus terlebih dahulu meminta pengguna untuk memilih faktor kedua yang ingin mereka gunakan. Anda bisa mendapatkan daftar faktor kedua yang didukung dengan memeriksa properti hints dari instance MultiFactorResolver:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. Jika pengguna memilih untuk menggunakan TOTP, minta mereka mengetik TOTP yang ditampilkan di aplikasi pengautentikasi mereka dan menggunakannya untuk login:

    let multiFactorInfo = resolver.hints[selectedIndex]
    switch multiFactorInfo.factorID {
    case TOTPMultiFactorID:
        let otpFromAuthenticator = // OTP typed by the user.
        let assertion = TOTPMultiFactorGenerator.assertionForSignIn(
            withEnrollmentID: multiFactorInfo.uid,
            oneTimePassword: otpFromAuthenticator)
        do {
            let authResult = try await resolver.resolveSignIn(with: assertion)
        } catch {
            // Wrong or expired OTP. Re-prompt the user.
        }
    default:
        return
    }
    

Membatalkan pendaftaran dari TOTP MFA

Bagian ini menjelaskan cara menangani pengguna yang membatalkan pendaftaran dari TOTP MFA.

Jika pengguna telah mendaftar untuk beberapa opsi MFA, dan jika mereka membatalkan pendaftaran dari opsi yang terakhir diaktifkan, mereka akan menerima auth/user-token-expired dan logout. Pengguna harus login lagi dan memverifikasi kredensial yang ada—misalnya, alamat email dan sandi.

Untuk membatalkan pendaftaran pengguna, menangani error, dan memicu autentikasi ulang, gunakan kode berikut:

guard let currentUser = Auth.auth().currentUser else { return }

// Prompt the user to select a factor to unenroll, from this array:
currentUser.multiFactor.enrolledFactors

// ...

// Unenroll the second factor.
let multiFactorInfo = currentUser.multiFactor.enrolledFactors[selectedIndex]
do {
    try await currentUser.multiFactor.unenroll(with: multiFactorInfo)
} catch let error as AuthErrorCode where error.code == .invalidUserToken {
    // Second factor unenrolled, but the user was signed out. Re-authenticate
    // them.
}

Langkah berikutnya