Signing in users with SAML

This document shows you how to use Identity Platform to sign in users with a Security Assertion Markup Language (SAML) 2.0 provider.

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Enable Identity Platform, and add the client SDK to your app. For more information and instructions, see the Sign in a user with an email by using Identity Platform quickstart.

Configure the provider

  1. In the Google Cloud console, go to the Identity Platform > Identity providers page.
    Go to Identity providers

  2. Click Add a Provider, and select SAML from the list.

  3. Enter the following details:

    1. The Name of the provider. This can be the same as the provider ID or a custom name. If you enter a custom name, click Edit next to Provider ID to specify the ID (which must begin with saml).

    2. The provider's Entity ID.

    3. The provider's SAML SSO URL.

    4. The certificate used for token-signing on the provider. Make sure to include the start and end strings. For example:

      -----BEGIN CERTIFICATE-----
      MIICajCCAdOgAwIBAgIBADANBgkqhkiG9w0BAQ0FADBSMQswCQYDVQQGEwJ1czEL
      ...
      LEzc1JwEGQQVDYQCwsQMSBDAF0QAB0w9GikhqkgBNADABIgABIwAgOdACCjaCIIM
      -----END CERTIFICATE-----
      
  4. In the Service provider section, enter the Entity ID of your app. This is typically your app's URL. On your SAML identity provider, this is referred to as the audience.

  5. In the Project settings side pane, click Add Domain, and add your app's domain. For example, if your app's sign-in URL is https://example.com/login, add example.com.

  6. To complete the setup, do one of the following:

    • Copy the default authorization callback URL from the Authorization callback (URL) field and add it to your SAML app configuration.

      Using the default authorization callback URL reduces the complexity of validating the SAML response.

    • Add your customized authorization callback URL to your SAML app configuration—for example, https://PROJECT-ID.firebaseapp.com/__/auth/handler.

  7. In the Configure your application section, click Setup Details. Copy the snippet into your app's code to initialize the Identity Platform client SDK.

  8. Click Save.

Provider required elements

Identity Platform expects the <saml:Subject> and <saml:NameID> elements in responses from the provider. If you don't define values for these elements when configuring your provider, the SAML assertion fails.

Sign requests

You can increase the security of your authentication requests by signing them.

To sign requests, first enable signed requests for your identity provider by calling inboundSamlConfigs.patch() and setting idp_config.sign_request to true:

REST

Before using any of the request data, make the following replacements:

  • project-id: the ID for the Google Cloud project
  • provider-id: the SAML provider ID

HTTP method and URL:

PATCH https://identitytoolkit.googleapis.com/admin/v2/projects/project-id/inboundSamlConfigs/provider-id?updateMask=idpConfig.signRequest

Request JSON body:

{
  "idp_config": {
    "sign_request": true
  }
}

To send your request, expand one of these options:

 

You must use the REST API to enable signed requests; using the Google Cloud console or Google Cloud CLI is not supported.

The response is an InboundSamlConfig object, which includes an array of SpCertificate. Configure the value of the X509 certificate with your SAML identity provider so it can validate the signature of your requests.

Sign in users

When you sign a user in, the client SDK handles the authentication handshake, then returns ID tokens containing the SAML attributes in their payloads. To sign a user in and get attributes from the SAML provider:

  1. Create a SAMLAuthProvider instance with the provider ID you configured in the previous section. The provider ID must start with saml.

    Web version 9

    import { SAMLAuthProvider } from "firebase/auth";
    
    const provider = new SAMLAuthProvider("saml.myProvider");

    Web version 8

    const provider = new firebase.auth.SAMLAuthProvider('saml.myProvider');
  2. Start the sign in flow. You can choose to either use a popup or a redirect.

    Web version 9

    import { getAuth, signInWithPopup, SAMLAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    signInWithPopup(auth, provider)
      .then((result) => {
        // User is signed in.
        // Provider data available from the result.user.getIdToken()
        // or from result.user.providerData
      }).catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The AuthCredential type that was used.
        const credential = SAMLAuthProvider.credentialFromError(error);
        // Handle / display error.
        // ...
      });

    Web version 8

    firebase.auth().signInWithPopup(provider)
      .then((result) => {
        // User is signed in.
        // Identity provider data available in result.additionalUserInfo.profile,
        // or from the user's ID token obtained from result.user.getIdToken()
        // as an object in the firebase.sign_in_attributes custom claim
        // This is also available from result.user.getIdTokenResult()
        // idTokenResult.claims.firebase.sign_in_attributes.
      })
      .catch((error) => {
        // Handle / display error.
        // ...
      });

    Redirect

    To redirect to a sign-in page, call signInWithRedirect():

    Web version 9

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);

    Web version 8

    firebase.auth().signInWithRedirect(provider);

    Then, call getRedirectResult() to get the results when the user returns to your app:

    Web version 9

    import { getAuth, getRedirectResult, SAMLAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        // User is signed in.
        // Provider data available from the result.user.getIdToken()
        // or from result.user.providerData
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The AuthCredential type that was used.
        const credential = SAMLAuthProvider.credentialFromError(error);
        // Handle / display error.
        // ...
      });

    Web version 8

    firebase.auth().getRedirectResult()
      .then((result) => {
        // User is signed in.
        // Provider data available in result.additionalUserInfo.profile,
        // or from the user's ID token obtained from result.user.getIdToken()
        // as an object in the firebase.sign_in_attributes custom claim
        // This is also available from result.user.getIdTokenResult()
        // idTokenResult.claims.firebase.sign_in_attributes.
      }).catch((error) => {
        // Handle / display error.
        // ...
      });
  3. Retrieve the user attributes associated with the SAML provider from the ID token using the firebase.sign_in_attributes claim. Make sure to verify the ID token using the Admin SDK when you send it to your server.

    The ID token includes the user's email address only if it is provided in the NameID attribute of the SAML assertion from the identity provider:

    <Subject>
      <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">test@email.com</NameID>
    </Subject>
    

    This is populated in the Firebase-issued ID token and in the UserInfo object.

Only service-provider initiated SAML flows from the client SDK are supported.

If a user has already signed in to your app using a different method (such as email/password), you can link their existing account to the SAML provider by using linkWithPopup() or linkWithRedirect().

The following code snippet shows how to link a user's Google Account to the SAML provider:

Web version 9

import { getAuth, linkWithPopup, GoogleAuthProvider } from "firebase/auth";
const provider = new GoogleAuthProvider();

const auth = getAuth();
linkWithPopup(auth.currentUser, provider).then((result) => {
  // Accounts successfully linked.
  const credential = GoogleAuthProvider.credentialFromResult(result);
  const user = result.user;
  // ...
}).catch((error) => {
  // Handle Errors here.
  // ...
});

Web version 8

auth.currentUser.linkWithPopup(provider).then((result) => {
  // Accounts successfully linked.
  var credential = result.credential;
  var user = result.user;
  // ...
}).catch((error) => {
  // Handle Errors here.
  // ...
});

What's next