Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Cloud Functions'ı engelleyerek Firebase Authentication'ı genişletin

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

Firebase Authentication with Identity Platform'a yükselttiyseniz, Cloud Functions'ı engelleyerek Firebase Authentication'ı genişletebilirsiniz.

Engelleme işlevleri, uygulamanıza kaydolan veya oturum açan bir kullanıcının sonucunu değiştiren özel kod yürütmenize olanak tanır. Örneğin, belirli kriterleri karşılamayan bir kullanıcının kimliğini doğrulamasını engelleyebilir veya bir kullanıcının bilgilerini istemci uygulamanıza döndürmeden önce güncelleyebilirsiniz.

Sen başlamadan önce

Engelleme işlevlerini kullanmak için Firebase projenizi Identity Platform ile Firebase Authentication'a yükseltmeniz gerekir. Henüz yükseltmediyseniz, önce bunu yapın.

Engelleme işlevlerini anlama

İki olay için engelleme işlevlerini kaydedebilirsiniz:

  • beforeCreate : Firebase Authentication veritabanına yeni bir kullanıcı kaydedilmeden ve istemci uygulamanıza bir jeton döndürülmeden önce tetiklenir.

  • beforeSignIn : Bir kullanıcının kimlik bilgileri doğrulandıktan sonra, ancak Firebase Authentication istemci uygulamanıza bir kimlik belirteci döndürmeden önce tetiklenir. Uygulamanız çok faktörlü kimlik doğrulama kullanıyorsa, kullanıcı ikinci faktörünü doğruladıktan sonra işlev tetiklenir. Yeni bir kullanıcı oluşturmanın, beforeSignIn ek olarak beforeCreate de tetiklediğini unutmayın.

Engelleme işlevlerini kullanırken aşağıdakileri aklınızda bulundurun:

  • İşleviniz 7 saniye içinde yanıt vermelidir. 7 saniye sonra Firebase Authentication bir hata döndürür ve istemci işlemi başarısız olur.

  • 200 farklı HTTP yanıt kodları, istemci uygulamalarınıza iletilir. İstemci kodunuzun, işlevinizin döndürebileceği hataları işlediğinden emin olun.

  • İşlevler, bir kiracıda bulunanlar da dahil olmak üzere projenizdeki tüm kullanıcılar için geçerlidir. Firebase Authentication, buna göre yanıt verebilmeniz için, ait oldukları kiracılar da dahil olmak üzere işleviniz için kullanıcılar hakkında bilgi sağlar.

  • Başka bir kimlik sağlayıcıyı bir hesaba bağlamak, tüm kayıtlı beforeSignIn işlevlerini yeniden tetikler.

  • Anonim ve özel kimlik doğrulama, engelleme işlevlerini tetiklemez.

Bir engelleme işlevi dağıtın ve kaydedin

Özel kodunuzu kullanıcı kimlik doğrulama akışlarına eklemek için engelleme işlevlerini dağıtın ve kaydedin. Engelleme işlevleriniz dağıtılıp kaydedildikten sonra, kimlik doğrulama ve kullanıcı oluşturma işleminin başarılı olması için özel kodunuzun başarıyla tamamlanması gerekir.

Bir engelleme işlevi dağıtın

Engelleme işlevini, herhangi bir işlevi dağıttığınız gibi dağıtırsınız. (ayrıntılar için Bulut İşlevleri Başlarken sayfasına bakın). Özetle:

  1. beforeCreate olayını, beforeSignIn olayını veya her ikisini birden işleyen Bulut İşlevleri yazın.

    Örneğin, başlamak için index.js aşağıdaki işlemsiz işlevleri ekleyebilirsiniz:

    const functions = require('firebase-functions');
    
    exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
      // TODO
    });
    
    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      // TODO
    });
    

    Yukarıdaki örnekler, özel yetkilendirme mantığının uygulanmasını atlamıştır. Engelleme işlevlerinizi nasıl uygulayacağınızı öğrenmek için aşağıdaki bölümlere ve belirli örnekler için Ortak senaryolara bakın.

  2. Firebase CLI'yi kullanarak işlevlerinizi dağıtın:

    firebase deploy --only functions
    

    İşlevlerinizi her güncellediğinizde yeniden dağıtmanız gerekir.

Bir engelleme işlevi kaydedin

  1. Firebase konsolundaki Firebase Kimlik Doğrulama Ayarları sayfasına gidin.

  2. Engelleme işlevleri sekmesini seçin.

  3. Hesap oluşturmadan önce (beforeCreate) veya Oturum açmadan önce (beforeSignIn) altındaki açılır menüden seçerek engelleme işlevinizi kaydedin.

  4. Değişikliklerinizi kaydedin.

Kullanıcı ve bağlam bilgilerini alma

beforeSignIn ve beforeCreate olayları, kullanıcının oturum açmasıyla ilgili bilgileri içeren User ve EventContext nesneleri sağlar. Bir işlemin devam etmesine izin verilip verilmeyeceğini belirlemek için kodunuzda bu değerleri kullanın.

User nesnesinde kullanılabilen özelliklerin listesi için UserRecord API başvurusuna bakın.

EventContext nesnesi aşağıdaki özellikleri içerir:

İsim Tanım Örnek
locale Uygulama yerel ayarı. Yerel ayarı, istemci SDK'sını kullanarak veya yerel ayar başlığını REST API'sine ileterek ayarlayabilirsiniz. fr veya sv-SE
ipAddress Son kullanıcının kaydolduğu veya oturum açtığı cihazın IP adresi. 114.14.200.1
userAgent Engelleme işlevini tetikleyen kullanıcı aracısı. Mozilla/5.0 (X11; Linux x86_64)
eventId Etkinliğin benzersiz tanımlayıcısı. rWsyPtolplG2TBFoOkkgyg
eventType Etkinlik türü. Bu, beforeSignIn veya beforeCreate gibi etkinlik adı ve Google veya e-posta/parola gibi kullanılan ilişkili oturum açma yöntemi hakkında bilgi sağlar. providers/cloud.auth/eventTypes/user.beforeSignIn:password
authType Her zaman USER . USER
resource Firebase Kimlik Doğrulama projesi veya kiracısı. projects/ project-id /tenants/ tenant-id
timestamp Olayın tetiklendiği, RFC 3339 dizesi olarak biçimlendirilmiş zaman. Tue, 23 Jul 2019 21:10:57 GMT
additionalUserInfo Kullanıcı hakkında bilgi içeren bir nesne. AdditionalUserInfo
credential Kullanıcının kimlik bilgileri hakkında bilgi içeren bir nesne. AuthCredential

Kayıt veya oturum açmayı engelleme

Bir kayıt veya oturum açma girişimini engellemek için işlevinize bir HttpsError atın. Örneğin:

Node.js

throw new functions.auth.HttpsError('permission-denied');

Aşağıdaki tablo, oluşturabileceğiniz hataları varsayılan hata iletileriyle birlikte listeler:

İsim kod İleti
invalid-argument 400 İstemci geçersiz bir bağımsız değişken belirtti.
failed-precondition 400 Mevcut sistem durumunda istek yürütülemez.
out-of-range 400 İstemci geçersiz bir aralık belirtti.
unauthenticated 401 Eksik, geçersiz veya süresi dolmuş OAuth jetonu.
permission-denied 403 İstemcinin yeterli izni yok.
not-found 404 Belirtilen kaynak bulunamadı.
aborted 409 Okuma-değiştirme-yazma çakışması gibi eşzamanlılık çakışması.
already-exists 409 İstemcinin oluşturmaya çalıştığı kaynak zaten var.
resource-exhausted 429 Ya kaynak kotası dışında ya da hız sınırlamasına ulaşılıyor.
cancelled 499 İstemci tarafından iptal edilen istek.
data-loss 500 Kurtarılamaz veri kaybı veya veri bozulması.
unknown 500 Bilinmeyen sunucu hatası.
internal 500 İç Sunucu Hatası.
not-implemented 501 API yöntemi sunucu tarafından uygulanmadı.
unavailable 503 Hizmet kullanılamıyor.
deadline-exceeded 504 Talep süresi aşıldı.

Ayrıca özel bir hata mesajı da belirtebilirsiniz:

Node.js

throw new functions.auth.HttpsError('permission-denied', 'Unauthorized request origin!');

Aşağıdaki örnek, belirli bir etki alanında olmayan kullanıcıların uygulamanıza kaydolmasını nasıl engelleyeceğinizi gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  // (If the user is authenticating within a tenant context, the tenant ID can be determined from
  // user.tenantId or from context.resource, e.g. 'projects/project-id/tenant/tenant-id-1')

  // Only users of a specific domain can sign up.
  if (user.email.indexOf('@acme.com') === -1) {
    throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

Varsayılan mı yoksa özel bir mesaj mı kullandığınızdan bağımsız olarak, Cloud Functions hatayı sarar ve istemciye dahili bir hata olarak döndürür. Örneğin:

throw new functions.auth.HttpsError('invalid-argument', `Unauthorized email user@evil.com}`);

Uygulamanız hatayı yakalamalı ve buna göre işlemelidir. Örneğin:

JavaScript

// Blocking functions can also be triggered in a multi-tenant context before user creation.
// firebase.auth().tenantId = 'tenant-id-1';
firebase.auth().createUserWithEmailAndPassword('johndoe@example.com', 'password')
  .then((result) => {
    result.user.getIdTokenResult()
  })
  .then((idTokenResult) => {
    console.log(idTokenResult.claim.admin);
  })
  .catch((error) => {
    if (error.code !== 'auth/internal-error' && error.message.indexOf('Cloud Function') !== -1) {
      // Display error.
    } else {
      // Registration succeeds.
    }
  });

Bir kullanıcıyı değiştirme

Bir kayıt veya oturum açma girişimini engellemek yerine işlemin devam etmesine izin verebilirsiniz, ancak Firebase Authentication'ın veritabanına kaydedilen ve istemciye döndürülen User nesnesini değiştirebilirsiniz.

Bir kullanıcıyı değiştirmek için olay işleyicinizden değiştirilecek alanları içeren bir nesne döndürün. Aşağıdaki alanları değiştirebilirsiniz:

  • displayName
  • disabled
  • emailVerified
  • photoURL
  • customClaims
  • sessionClaims (yalnızca beforeSignIn )

sessionClaims dışında, değiştirilen tüm alanlar Firebase Authentication'ın veritabanına kaydedilir; bu, yanıt belirtecine dahil edildikleri ve kullanıcı oturumları arasında kalıcı oldukları anlamına gelir.

Aşağıdaki örnek, varsayılan bir görünen adın nasıl ayarlanacağını gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  return {
    // If no display name is provided, set it to "Guest".
    displayName: user.displayName || 'Guest';
  };
});

Hem beforeCreate hem de BeforeSignIn için bir olay işleyicisi beforeSignIn , beforeSignIn sonrasında beforeCreate unutmayın. beforeSignIn içinde güncellenen kullanıcı alanları beforeCreate içinde görünür. Her iki olay işleyicide de sessionClaims dışında bir alan ayarlarsanız, BeforeSignIn içinde ayarlanan değer, beforeSignIn içinde ayarlanan değerin üzerine beforeCreate . Yalnızca sessionClaims için, geçerli oturumun belirteç taleplerine yayılırlar, ancak kalıcı değildir veya veritabanında depolanmaz.

Örneğin, herhangi bir sessionClaims ayarlanmışsa, beforeSignIn bunları herhangi bir beforeCreate talebiyle birlikte döndürür ve bunlar birleştirilir. Birleştirildiğinde, bir sessionClaims anahtarı customClaims içindeki bir anahtarla eşleşirse, sessionClaims anahtarı tarafından belirteç taleplerinde eşleşen customClaims üzerine yazılır. Ancak, üzerine yazılan customClaims anahtarı, gelecekteki istekler için veritabanında kalmaya devam edecektir.

Desteklenen OAuth kimlik bilgileri ve verileri

Çeşitli kimlik sağlayıcılarından gelen engelleme işlevlerine OAuth kimlik bilgilerini ve verilerini iletebilirsiniz. Aşağıdaki tablo, her bir kimlik sağlayıcı için hangi kimlik bilgilerinin ve verilerin desteklendiğini gösterir:

Kimlik Sağlayıcı Kimlik Simgesi Erişim Simgesi Son Kullanma Süresi Jeton Sırrı Simgeyi Yenile Oturum Açma Talepleri
Google Evet Evet Evet Numara Evet Numara
Facebook Numara Evet Evet Numara Numara Numara
heyecan Numara Evet Numara Evet Numara Numara
GitHub Numara Evet Numara Numara Numara Numara
Microsoft Evet Evet Evet Numara Evet Numara
LinkedIn Numara Evet Evet Numara Numara Numara
yahoo Evet Evet Evet Numara Evet Numara
Elma Evet Evet Evet Numara Evet Numara
SAML Numara Numara Numara Numara Numara Evet
OIDC Evet Evet Evet Numara Evet Evet

Jetonları yenile

Bir engelleme işlevinde yenileme belirteci kullanmak için önce Firebase konsolunun Engelleme işlevleri sayfasındaki onay kutusunu seçmelisiniz.

Kimlik belirteci veya erişim belirteci gibi bir OAuth kimlik bilgisi ile doğrudan oturum açarken herhangi bir kimlik sağlayıcısı tarafından yenileme belirteçleri döndürülmez. Bu durumda, aynı istemci tarafı OAuth kimlik bilgisi engelleme işlevine iletilecektir.

Aşağıdaki bölümlerde, her bir kimlik sağlayıcı türü ve bunların desteklenen kimlik bilgileri ve verileri açıklanmaktadır.

Genel OIDC sağlayıcıları

Bir kullanıcı, genel bir OIDC sağlayıcısı ile oturum açtığında, aşağıdaki kimlik bilgileri iletilecektir:

  • Kimlik belirteci : id_token akışı seçilirse sağlanır.
  • Erişim belirteci : Kod akışı seçilirse sağlanır. Kod akışının şu anda yalnızca REST API aracılığıyla desteklendiğini unutmayın.
  • Yenileme belirteci : offline_access kapsamı seçiliyse sağlanır.

Örnek:

const provider = new firebase.auth.OAuthProvider('oidc.my-provider');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

Google

Bir kullanıcı Google ile oturum açtığında aşağıdaki kimlik bilgileri iletilir:

  • kimlik belirteci
  • Erişim belirteci
  • Yenileme belirteci : Yalnızca aşağıdaki özel parametreler istenirse sağlanır:
    • access_type=offline
    • prompt=consent , kullanıcı daha önce izin verdiyse ve yeni bir kapsam istenmediyse

Örnek:

const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({
  'access_type': 'offline',
  'prompt': 'consent'
});
firebase.auth().signInWithPopup(provider);

Google yenileme belirteçleri hakkında daha fazla bilgi edinin.

Facebook

Bir kullanıcı Facebook ile oturum açtığında, aşağıdaki kimlik bilgileri iletilecektir:

  • Erişim belirteci : Başka bir erişim belirteci ile değiştirilebilen bir erişim belirteci döndürülür. Facebook tarafından desteklenen farklı erişim belirteçleri türleri ve bunları uzun ömürlü belirteçlerle nasıl değiştirebileceğiniz hakkında daha fazla bilgi edinin.

GitHub

Bir kullanıcı GitHub ile oturum açtığında aşağıdaki kimlik bilgileri iletilecektir:

  • Erişim belirteci : İptal edilmediği sürece süresi dolmaz.

Microsoft

Bir kullanıcı Microsoft ile oturum açtığında aşağıdaki kimlik bilgileri iletilecektir:

  • kimlik belirteci
  • Erişim belirteci
  • Yenileme belirteci : offline_access kapsamı seçiliyse engelleme işlevine iletilir.

Örnek:

const provider = new firebase.auth.OAuthProvider('microsoft.com');
provider.addScope('offline_access');
firebase.auth().signInWithPopup(provider);

yahoo

Bir kullanıcı Yahoo ile oturum açtığında, aşağıdaki kimlik bilgileri herhangi bir özel parametre veya kapsam olmadan iletilecektir:

  • kimlik belirteci
  • Erişim belirteci
  • Simgeyi yenile

LinkedIn

Bir kullanıcı LinkedIn ile oturum açtığında aşağıdaki kimlik bilgileri iletilecektir:

  • Erişim belirteci

Elma

Bir kullanıcı Apple ile oturum açtığında, aşağıdaki kimlik bilgileri herhangi bir özel parametre veya kapsam olmadan iletilecektir:

  • kimlik belirteci
  • Erişim belirteci
  • Simgeyi yenile

Ortak senaryolar

Aşağıdaki örnekler, işlevleri engellemek için bazı yaygın kullanım durumlarını göstermektedir:

Yalnızca belirli bir alan adından kayıt yapılmasına izin verilmesi

Aşağıdaki örnek, example.com alan adının parçası olmayan kullanıcıların uygulamanıza kaydolmasını nasıl engelleyeceğinizi gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (!user.email || user.email.indexOf('@example.com') === -1) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unauthorized email "${user.email}"`);
  }
});

Doğrulanmamış e-postaları olan kullanıcıların kaydolmasını engelleme

Aşağıdaki örnek, doğrulanmamış e-postaları olan kullanıcıların uygulamanıza kaydolmasını nasıl engelleyeceğinizi gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified) {
    throw new functions.auth.HttpsError(
      'invalid-argument', `Unverified email "${user.email}"`);
  }
});

Kayıt sırasında e-posta doğrulamasının gerekli olması

Aşağıdaki örnek, bir kullanıcının kaydolduktan sonra e-postasını doğrulamasının nasıl isteneceğini gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  const locale = context.locale;
  if (user.email && !user.emailVerified) {
    // Send custom email verification on sign-up.
    return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
      return sendCustomVerificationEmail(user.email, link, locale);
    });
  }
});

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
 if (user.email && !user.emailVerified) {
   throw new functions.auth.HttpsError(
     'invalid-argument', `"${user.email}" needs to be verified before access is granted.`);
  }
});

Belirli kimlik sağlayıcı e-postalarını doğrulanmış olarak ele alma

Aşağıdaki örnek, belirli kimlik sağlayıcılarından gelen kullanıcı e-postalarının doğrulanmış olarak nasıl ele alınacağını gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.email && !user.emailVerified && context.eventType.indexOf(':facebook.com') !== -1) {
    return {
      emailVerified: true,
    };
  }
});

Belirli IP adreslerinden oturum açmayı engelleme

Aşağıdaki örnek, belirli IP adresi aralıklarından oturum açmanın nasıl engelleneceğini gösterir:

Node.js

exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
  if (isSuspiciousIpAddress(context.ipAddress)) {
    throw new functions.auth.HttpsError(
      'permission-denied', 'Unauthorized access!');
  }
});

Özel ve oturum taleplerini ayarlama

Aşağıdaki örnek, özel ve oturum taleplerinin nasıl ayarlanacağını gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'saml.my-provider-id') {
    return {
      // Employee ID does not change so save in persistent claims (stored in
      // Auth DB).
      customClaims: {
        eid: context.credential.claims.employeeid,
      },
      // Copy role and groups to token claims. These will not be persisted.
      sessionClaims: {
        role: context.credential.claims.role,
        groups: context.credential.claims.groups,
      }
    }
  }
});

Şüpheli etkinliği izlemek için IP adreslerini izleme

Bir kullanıcının oturum açtığı IP adresini izleyerek ve sonraki isteklerde bu IP adresiyle karşılaştırarak belirteç hırsızlığını önleyebilirsiniz. İstek şüpheli görünüyorsa (örneğin, IP'ler farklı coğrafi bölgelerden geliyorsa) kullanıcıdan tekrar oturum açmasını isteyebilirsiniz.

  1. Kullanıcının oturum açtığı IP adresini izlemek için oturum taleplerini kullanın:

    Node.js

    exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
      return {
        sessionClaims: {
          signInIpAddress: context.ipAddress,
        },
      };
    });
    
  2. Bir kullanıcı Firebase Authentication ile kimlik doğrulaması gerektiren kaynaklara erişmeye çalıştığında, istekteki IP adresini oturum açmak için kullanılan IP ile karşılaştırın:

    Node.js

    app.post('/getRestrictedData', (req, res) => {
      // Get the ID token passed.
      const idToken = req.body.idToken;
      // Verify the ID token, check if revoked and decode its payload.
      admin.auth().verifyIdToken(idToken, true).then((claims) => {
        // Get request IP address
        const requestIpAddress = req.connection.remoteAddress;
        // Get sign-in IP address.
        const signInIpAddress = claims.signInIpAddress;
        // Check if the request IP address origin is suspicious relative to
        // the session IP addresses. The current request timestamp and the
        // auth_time of the ID token can provide additional signals of abuse,
        // especially if the IP address suddenly changed. If there was a sudden
        // geographical change in a short period of time, then it will give
        // stronger signals of possible abuse.
        if (!isSuspiciousIpAddressChange(signInIpAddress, requestIpAddress)) {
          // Suspicious IP address change. Require re-authentication.
          // You can also revoke all user sessions by calling:
          // admin.auth().revokeRefreshTokens(claims.sub).
          res.status(401).send({error: 'Unauthorized access. Please login again!'});
        } else {
          // Access is valid. Try to return data.
          getData(claims).then(data => {
            res.end(JSON.stringify(data);
          }, error => {
            res.status(500).send({ error: 'Server error!' })
          });
        }
      });
    });
    

Kullanıcı fotoğraflarının taranması

Aşağıdaki örnek, kullanıcıların profil fotoğraflarının nasıl sterilize edileceğini gösterir:

Node.js

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (user.photoURL) {
    return isPhotoAppropriate(user.photoURL)
      .then((status) => {
        if (!status) {
          // Sanitize inappropriate photos by replacing them with guest photos.
          // Users could also be blocked from sign-up, disabled, etc.
          return {
            photoURL: PLACEHOLDER_GUEST_PHOTO_URL,
          };
        }
      });
});

Görüntülerin nasıl algılanacağı ve sterilize edileceği hakkında daha fazla bilgi edinmek için Cloud Vision belgelerine bakın.

Bir kullanıcının kimlik sağlayıcısı OAuth kimlik bilgilerine erişme

Aşağıdaki örnek, Google ile oturum açmış bir kullanıcı için yenileme belirtecinin nasıl alınacağını ve bunu Google Takvim API'lerini çağırmak için nasıl kullanılacağını gösterir. Yenileme belirteci çevrimdışı erişim için saklanır.

Node.js

const {OAuth2Client} = require('google-auth-library');
const {google} = require('googleapis');
// ...
// Initialize Google OAuth client.
const keys = require('./oauth2.keys.json');
const oAuth2Client = new OAuth2Client(
  keys.web.client_id,
  keys.web.client_secret
);

exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
  if (context.credential &&
      context.credential.providerId === 'google.com') {
    // Store the refresh token for later offline use.
    // These will only be returned if refresh tokens credentials are included
    // (enabled by Cloud console).
    return saveUserRefreshToken(
        user.uid,
        context.credential.refreshToken,
        'google.com'
      )
      .then(() => {
        // Blocking the function is not required. The function can resolve while
        // this operation continues to run in the background.
        return new Promise((resolve, reject) => {
          // For this operation to succeed, the appropriate OAuth scope should be requested
          // on sign in with Google, client-side. In this case:
          // https://www.googleapis.com/auth/calendar
          // You can check granted_scopes from within:
          // context.additionalUserInfo.profile.granted_scopes (space joined list of scopes).

          // Set access token/refresh token.
          oAuth2Client.setCredentials({
            access_token: context.credential.accessToken,
            refresh_token: context.credential.refreshToken,
          });
          const calendar = google.calendar('v3');
          // Setup Onboarding event on user's calendar.
          const event = {/** ... */};
          calendar.events.insert({
            auth: oauth2client,
            calendarId: 'primary',
            resource: event,
          }, (err, event) => {
            // Do not fail. This is a best effort approach.
            resolve();
          });
      });
    })
  }
});