To use external identities with Identity-Aware Proxy (IAP), your app needs a sign-in page. IAP will redirect users to this page to authenticate before they can access secure resources.
This article shows you how to build an authentication page using FirebaseUI , an open-source JavaScript library. FirebaseUI provides customizable elements that help reduce boilerplate code, and handles the flows for signing in users with a wide range of identity providers.
To get started faster, let IAP host the UI for you . This lets you try external identities without writing any additional code. For more advanced scenarios, you can also build your own sign-in page from scratch . This option is more complex, but gives you full control over the authentication flow and user experience.
Before you begin
Enable external identities , and select the I'll provide my own UIoption during setup.
Installing the libraries
Install the gcip-iap
, firebase
, and firebaseui
libraries. The gcip-iap
module abstracts communications between your app,
IAP, and Identity Platform. The firebase
and firebaseui
libraries provide the building blocks for your authentication UI.
npm install firebase --save
npm install firebaseui --save
npm install gcip-iap --save
Note that the gcip-iap
module is not available using CDN.
You can then import
the modules in your source files. Use the correct imports for your SDK version:
gcip-iap v0.1.4 or earlier
//
Import
firebase
modules
.
import
*
as
firebase
from
"firebase/app"
;
import
"firebase/auth"
;
//
Import
firebaseui
module
.
import
*
as
firebaseui
from
'firebaseui'
//
Import
gcip
-
iap
module
.
import
*
as
ciap
from
'gcip-iap'
;
gcip-iap v1.0.0 or later
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
andfirebaseui
versions in yourpackage.json
file to v9.6.0+ and v6.0.0+ respectively. - Update the
firebase
import statements as follows:
//
Import
firebase
modules
.
import
firebase
from
'firebase/compat/app'
;
import
'firebase/compat/auth'
;
//
Import
firebaseui
module
.
import
*
as
firebaseui
from
'firebaseui'
//
Import
gcip
-
iap
module
.
No additional code changes are needed.
For additional installation options, including using localized versions of the libraries, refer to the instructions on GitHub .
Configuring your application
FirebaseUI uses a configuration object that specifies the tenants and providers to use for authentication. A full configuration can be very long, and might look something like this:
//
The
project
configuration
.
const
configs
=
{
//
Configuration
for
project
identified
by
API
key
API_KEY1
.
API_KEY1
:
{
authDomain
:
'project-id1.firebaseapp.com'
,
//
Decide
whether
to
ask
user
for
identifier
to
figure
out
//
what
tenant
to
select
or
whether
to
present
all
the
tenants
to
select
from
.
displayMode
:
'optionFirst'
,
//
Or
identifierFirst
//
The
terms
of
service
URL
and
privacy
policy
URL
for
the
page
//
where
the
user
select
tenant
or
enter
email
for
tenant
/
provider
//
matching
.
tosUrl
:
'http://localhost/tos'
,
privacyPolicyUrl
:
'http://localhost/privacypolicy'
,
callbacks
:
{
//
The
callback
to
trigger
when
the
selection
tenant
page
//
or
enter
email
for
tenant
matching
page
is
shown
.
selectTenantUiShown
:
()
=
>
{
//
Show
title
and
additional
display
info
.
},
//
The
callback
to
trigger
when
the
sign
-
in
page
//
is
shown
.
signInUiShown
:
(
tenantId
)
=
>
{
//
Show
tenant
title
and
additional
display
info
.
},
beforeSignInSuccess
:
(
user
)
=
>
{
//
Do
additional
processing
on
user
before
sign
-
in
is
//
complete
.
return
Promise
.
resolve
(
user
);
}
},
tenants
:
{
//
Tenant
configuration
for
tenant
ID
tenantId1
.
tenantId1
:
{
//
Full
label
,
display
name
,
button
color
and
icon
URL
of
the
//
tenant
selection
button
.
Only
needed
if
you
are
//
using
the
option
first
option
.
fullLabel
:
'ACME Portal'
,
displayName
:
'ACME'
,
buttonColor
:
'#2F2F2F'
,
iconUrl
:
'<icon-url-of-sign-in-button>'
,
//
Sign
-
in
providers
enabled
for
tenantId1
.
signInOptions
:
[
//
Microsoft
sign
-
in
.
{
provider
:
'microsoft.com'
,
providerName
:
'Microsoft'
,
buttonColor
:
'#2F2F2F'
,
iconUrl
:
'<icon-url-of-sign-in-button>'
,
loginHintKey
:
'login_hint'
},
//
Email
/
password
sign
-
in
.
{
provider
:
'password'
,
//
Do
not
require
display
name
on
sign
up
.
requireDisplayName
:
false
,
disableSignUp
:
{
//
Disable
user
from
signing
up
with
email
providers
.
status
:
true
,
adminEmail
:
'admin@example.com'
,
helpLink
:
'https://www.example.com/trouble_signing_in'
}
},
//
SAML
provider
.
(
multiple
SAML
providers
can
be
passed
)
{
provider
:
'saml.my-provider1'
,
providerName
:
'SAML provider'
,
fullLabel
:
'Employee Login'
,
buttonColor
:
'#4666FF'
,
iconUrl
:
'https://www.example.com/photos/my_idp/saml.png'
},
],
//
If
there
is
only
one
sign
-
in
provider
eligible
for
the
user
,
//
whether
to
show
the
provider
selection
page
.
immediateFederatedRedirect
:
true
,
signInFlow
:
'redirect'
,
//
Or
popup
//
The
terms
of
service
URL
and
privacy
policy
URL
for
the
sign
-
in
page
//
specific
to
each
tenant
.
tosUrl
:
'http://localhost/tenant1/tos'
,
privacyPolicyUrl
:
'http://localhost/tenant1/privacypolicy'
},
//
Tenant
configuration
for
tenant
ID
tenantId2
.
tenantId2
:
{
fullLabel
:
'OCP Portal'
,
displayName
:
'OCP'
,
buttonColor
:
'#2F2F2F'
,
iconUrl
:
'<icon-url-of-sign-in-button>'
,
//
Tenant2
supports
a
SAML
,
OIDC
and
Email
/
password
sign
-
in
.
signInOptions
:
[
//
Email
/
password
sign
-
in
.
{
provider
:
firebase
.
auth
.
EmailAuthProvider
.
PROVIDER_ID
,
//
Do
not
require
display
name
on
sign
up
.
requireDisplayName
:
false
},
//
SAML
provider
.
(
multiple
SAML
providers
can
be
passed
)
{
provider
:
'saml.my-provider2'
,
providerName
:
'SAML provider'
,
fullLabel
:
'Contractor Portal'
,
buttonColor
:
'#4666FF'
,
iconUrl
:
'https://www.example.com/photos/my_idp/saml.png'
},
//
OIDC
provider
.
(
multiple
OIDC
providers
can
be
passed
)
{
provider
:
'oidc.my-provider1'
,
providerName
:
'OIDC provider'
,
buttonColor
:
'#4666FF'
,
iconUrl
:
'https://www.example.com/photos/my_idp/oidc.png'
},
],
},
//
Tenant
configuration
for
tenant
ID
tenantId3
.
tenantId3
:
{
fullLabel
:
'Tenant3 Portal'
,
displayName
:
'Tenant3'
,
buttonColor
:
'#007bff'
,
iconUrl
:
'<icon-url-of-sign-in-button>'
,
//
Tenant3
supports
a
Google
and
Email
/
password
sign
-
in
.
signInOptions
:
[
//
Email
/
password
sign
-
in
.
{
provider
:
firebase
.
auth
.
EmailAuthProvider
.
PROVIDER_ID
,
//
Do
not
require
display
name
on
sign
up
.
requireDisplayName
:
false
},
//
Google
provider
.
{
provider
:
'google.com'
,
scopes
:
[
'scope1'
,
'scope2'
,
'https://example.com/scope3'
],
loginHintKey
:
'login_hint'
,
customParameters
:
{
prompt
:
'consent'
,
},
},
],
//
Sets
the
adminRestrictedOperation
configuration
for
providers
//
including
federated
,
email
/
password
,
email
link
and
phone
number
.
adminRestrictedOperation
:
{
status
:
true
,
adminEmail
:
'admin@example.com'
,
helpLink
:
'https://www.example.com/trouble_signing_in'
}
},
},
},
};
The following sections provide guidance on how to configure some of the fields specific to IAP. For examples on setting other fields, see the code snippet above, or the FirebaseUI documentation on GitHub .
Setting the API key
A typical configuration begins with an API key for your project:
//
The
project
configuration
.
const
configs
=
{
//
Configuration
for
API_KEY
.
API_KEY
:
{
//
Config
goes
here
}
}
In most cases, you only need to specify a single API key. However, if you want to use a single authentication URL across multiple projects, you can include multiple API keys:
const
configs
=
{
API_KEY1
:
{
//
Config
goes
here
},
API_KEY2
:
{
//
Config
goes
here
},
}
Getting the authentication domain
Set the authdomain
field to the domain provisioned to facilitate federated
sign-in. You can retrieve this field from the Identity Platform page in the Google Cloud console
.
Specifying tenants IDs
A configuration requires a list of tenants and providers that users can authenticate with.
Each tenant is identified by its ID. If you're using project-level
authentication (no tenants), use the special _
identifier as an API key
instead. For example:
const
configs
=
{
//
Configuration
for
project
identified
by
API
key
API_KEY1
.
API_KEY1
:
{
tenants
:
{
//
Project
-
level
IdPs
flow
.
_
:
{
//
Tenant
config
goes
here
},
//
Single
tenant
flow
.
1036546636501
:
{
//
Tenant
config
goes
here
}
}
}
}
You can also specify a wildcard tenant configuration using the *
operator.
This tenant is used as a fallback if no matching ID is found.
Configuring tenant providers
Each tenant has its own providers; these are specified in the signInOptions
field:
tenantId1
:
{
signInOptions
:
[
// Options go here
]
}
See Configuring sign-in providers in the FirebaseUI documentation to learn how to configure providers.
In addition to the steps outlined in the FirebaseUI documentation, there are several fields specific to IAP that depend on the tenant selection mode you choose. See the next section for more information on these fields.
Choosing a tenant selection mode
Users can select a tenant in two ways: options-first mode, or identifier-first mode.
In options mode, the user begins by selecting a tenant from a list, then enters their username and password. In identifier mode, the user enters their email first. The system then automatically selects the first tenant with an identity provider matching the email's domain.
To use options mode, set displayMode
to optionFirst
. You'll then
need to provide configuration information for each tenant's button, including displayName
, buttonColor
, and iconUrl
. An optional fullLabel
can also
be provided to override the entire button label instead of just the display
name.
The following is an example of a tenant configured to use options mode:
tenantId1: {
fullLabel: 'ACME Portal',
displayName: 'ACME',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// ...
To use identifier mode, each sign-in option must specify an hd
field
indicating what domain it supports. This can be either a regex (such as /@example\.com$/
) or the domain string (e.g., example.com
).
The code below shows a tenant configured to use identifier mode:
tenantId1
:
{
signInOptions
:
[
//
Email
/
password
sign
-
in
.
{
hd
:
'acme.com'
,
//
using
regex
:
/
@acme
\
.
com
$
/
//
...
}
,
Enabling immediate redirect
If your app only supports a single identity provider, setting immediateFederatedRedirect
to true
will skip the sign-in UI and
redirect the user directly to the provider.
Setting up callbacks
The configuration object contains a set of callbacks that are invoked at various points during the authentication flow. This lets you additionally customize the UI. The following hooks are available:
selectTenantUiShown()
|
Triggered when the UI to select a tenant is shown. Use this if you want to modify the UI with a customized title or theme. |
signInUiShown(tenantId)
|
Triggered when a tenant is selected and the UI for the user to enter their credentials is shown. Use this if you want to modify the UI with a customized title or theme. |
beforeSignInSuccess(user)
|
Triggered before sign-in completes. Use this to modify a signed in user before redirecting back to the IAP resource. |
The following example code shows how you might implement these callbacks:
callbacks:
{
selectTenantUiShown:
()
=
>
{
//
Show
info
of
the
IAP
resource
.
showUiTitle
(
'Select your employer to access your Health Benefits'
);
},
signInUiShown:
(
tenantId
)
=
>
{
//
Show
tenant
title
and
additional
display
info
.
const
tenantName
=
getTenantNameFromId
(
tenantId
);
showUiTitle
(
`Sign in to access your ${tenantName} Health Benefits`
);
},
beforeSignInSuccess:
(
user
)
=
>
{
//
Do
additional
processing
on
user
before
sign
-
in
is
//
complete
.
//
For
example
update
the
user
profile
.
return
user
.
updateProfile
({
photoURL:
'https://example.com/profile/1234/photo.png'
,
})
.
then
(
function
()
{
//
To
reflect
updated
photoURL
in
the
ID
token
,
force
token
//
refresh
.
return
user
.
getIdToken
(
true
);
})
.
then
(
function
()
{
return
user
;
});
}
}
Initializing the library
Once you've created a configuration object, follow these steps to initialize the library on your authentication page:
-
Create an HTML container to render the UI in.
< !DOCTYPE html > < html > < head>...</head> < body > <! -- The surrounding HTML is left untouched by FirebaseUI . Your app may use that space for branding , controls and other customizations . -- > < h1>Welcome to My Awesome App < / h1 > < div id = "firebaseui-auth-container" >< / div > < / body > < / html >
-
Create a
FirebaseUiHandler
instance to render in the HTML container, and pass theconfig
element you created to it.const configs = { // ... } const handler = new firebaseui . auth . FirebaseUiHandler ( '#firebaseui-auth-container' , configs );
-
Create a new
Authentication
instance, pass the handler to it, and callstart()
.const ciapInstance = new ciap . Authentication ( handler ); ciapInstance . start ();
Deploy your application and navigate to the authentication page. A sign-in UI containing your tenants and providers should appear.
What's next
- Learn how to access non-Google resources programmatically .
- Learn about managing sessions .
- Gain a deeper understanding of how external identities work with IAP .