Creating a custom sign-in page

This article shows you how to build your own authentication page using external identities and IAP. Constructing this page yourself gives you full control over the authentication flow and user experience.

If you don't need to fully customize your UI, you can let IAP host a sign-in page for you, or use FirebaseUI for a more streamlined experience.

Overview

To build your own authentication page, follow these steps:

  1. Enable external identities. Select I'll provide my own UI option during setup.
  2. Install the gcip-iap library.
  3. Configure the UI by implementing the AuthenticationHandler interface. Your authentication page must handle the following scenarios:
    • Tenant selection
    • User authorization
    • User sign in
    • Error handling
  4. Optional: Customize your authentication page with additional features, such as progress bars, sign out pages, and user processing.
  5. Test your UI.

Installing the gcip-iap library

To install the gcip-iap library, run the following command:

npm install gcip-iap --save

The gcip-iap NPM module abstracts the communications between your application, IAP, and Identity Platform. This lets you customize the entire authentication flow without having to manage the underlying exchanges between the UI and IAP.

Use the correct imports for your SDK version:

gcip-iap v0.1.4 or earlier

// Import Firebase/GCIP dependencies. These are installed on npm install.
import * as firebase from 'firebase/app';
import 'firebase/auth';
// Import GCIP/IAP module.
import * as ciap from 'gcip-iap';

gcip-iap v1.0.0 to v1.1.0

Starting with version v1.0.0, gcip-iap requires the firebase v9 peer dependency or greater. If you are migrating to gcip-iap v1.0.0 or above, complete the following actions:

  • Update the firebase version in your package.json file to v9.6.0+.
  • Update the firebase import statements as follows:
// Import Firebase modules.
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
// Import the gcip-iap module.
import * as ciap from 'gcip-iap';

No additional code changes are needed.

gcip-iap v2.0.0

Starting with version v2.0.0, gcip-iap requires rewrite of your custom UI application using the modular SDK format. If you are migrating to gcip-iap v2.0.0 or above, complete the following actions:

  • Update the firebase version in your package.json file to v9.8.3+.
  • Update the firebase import statements as follows:
  // Import Firebase modules.
  import { initializeApp } from 'firebase/app';
  import { getAuth, GoogleAuthProvider } 'firebase/auth';
  // Import the gcip-iap module.
  import * as ciap from 'gcip-iap';

Configuring the UI

To configure the UI, create a custom class that implements the AuthenticationHandler interface:

interface AuthenticationHandler {
  languageCode?: string | null;
  getAuth(apiKey: string, tenantId: string | null): FirebaseAuth;
  startSignIn(auth: FirebaseAuth, match?: SelectedTenantInfo): Promise<UserCredential>;
  selectTenant?(projectConfig: ProjectConfig, tenantIds: string[]): Promise<SelectedTenantInfo>;
  completeSignOut(): Promise<void>;
  processUser?(user: User): Promise<User>;
  showProgressBar?(): void;
  hideProgressBar?(): void;
  handleError?(error: Error | CIAPError): void;
}

During authentication, the library automatically calls AuthenticationHandler's methods.

Selecting tenants

To select a tenant, implement selectTenant(). You can implement this method to choose a tenant programmatically, or display a UI so the user can select one themselves.

In either case, the library uses the returned SelectedTenantInfo object to complete the authentication flow. It contains the ID of the selected tenant, any provider IDs, and the email the user entered.

If you have multiple tenants in your project, you must select one before you can authenticate a user. If you only have a single tenant, or are using project-level authentication, you don't need to implement selectTenant().

IAP supports the same providers as Identity Platform, such as:

  • Email and password
  • OAuth (Google, Facebook, Twitter, GitHub, Microsoft, etc)
  • SAML
  • OIDC
  • Phone number
  • Custom
  • Anonymous

Phone number, custom, and anonymous authentication types are not supported for multi-tenancy.

Selecting tenants programmatically

To select a tenant programmatically, leverage the current context. The Authentication class contains getOriginalURL() that returns the URL the user was accessing before authentication.

Use this to locate a match from a list of associated tenants:

// Select provider programmatically.
selectTenant(projectConfig, tenantIds) {
  return new Promise((resolve, reject) => {
    // Show UI to select the tenant.
    auth.getOriginalURL()
      .then((originalUrl) => {
        resolve({
          tenantId: getMatchingTenantBasedOnVisitedUrl(originalUrl),
          // If associated provider IDs can also be determined,
          // populate this list.
          providerIds: [],
        });
      })
      .catch(reject);
  });
}

Allowing users to select tenants

To allow the user to select a tenant, display a list of tenants and have the user choose one, or ask them to enter their email address and then locate a match based on the domain:

// Select provider by showing UI.
selectTenant(projectConfig