Managing SAML and OIDC providers programmatically

This article shows you how to use the Identity Platform Admin SDK to manage Security Assertion Markup Language (SAML) 2.0 and OpenID Connect (OIDC) provider configurations programmatically.

Using the Admin SDK, you can automatically configure providers, perform basic CRUD operations, rotate certificates, and more. This is useful when you have a large number of providers that would be cumbersome to manage manually using the Cloud Console.

Before you begin

Working with SAML providers

Creating a SAML provider configuration

You'll need to supply the following parameters when creating a SAML provider configuration. You may need to consult your identity provider's documentation for details on how to obtain some of the values.

Display name
A user-friendly display name for the configuration. This name is also the provider label in the Cloud Console.
Enabled
Whether the current provider configuration is enabled or disabled. Users cannot sign in with disabled providers.
Provider ID
The provider's unique identifier, beginning with saml..
Identity provider entity ID
The entity ID for the provider.
SSO URL
The SAML SSO URL for the provider. The URL must be valid.
X.509 certificates

A list of SAML provider X.509 certificates, including the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE---- strings. These are used for token-signing on the identity provider.

When Identity Platform receives a SAML response, it will verify its signature using a certificate on record. If verification fails, the response will be rejected. You will need to update these certificates as keys are rotated. Consider uploading multiple certificates to prevent outages during rotations.

Relaying party entity ID
The SAML relying party (RP/SP) entity ID. This is commonly the URL of the app. On the SAML identity provider, this is referred to as the audience.
Callback URL

The URL to return to when authentication completes. SAML providers commonly refer to this as the Assertion Consumer Service (ACS) URL. You'll need to register this URL with the SAML provider. It should look something like https://PROJECT-ID.firebaseapp.com/__/auth/handler, similar to the URLs displayed in the Cloud Console. To learn more, see Signing in users with SAML.

Using the default callback URL will decrease the complexity of validating SAML responses. However, you can also choose to show a custom domain. In this case, make sure the Identity Platform callback URL for your project is properly correctly configured with your SAML identity provider. Typically, this looks something like https://AUTH-DOMAIN/__/auth/handler.

The following example demonstrates how to create a SAML provider configuration:

Node.js

const newConfig = {
  displayName: 'SAML provider name',
  enabled: true,
  providerId: 'saml.myProvider',
  idpEntityId: 'IDP_ENTITY_ID',
  ssoURL: 'https://example.com/saml/sso/1234/'
  x509Certificates: [
    '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
    '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
  ],
  rpEntityId: 'RP_ENTITY_ID',
  // Using the default callback URL.
  callbackURL: 'https://project-id.firebaseapp.com/__/auth/handler',
};
admin.auth().createProviderConfig(newConfig).then(() => {
  // Successful creation.
}).catch((error) => {
  // Handle error.
});

Go

newConfig := (&auth.SAMLProviderConfigToCreate{}).
	DisplayName("SAML provider name").
	Enabled(true).
	ID("saml.myProvider").
	IDPEntityID("IDP_ENTITY_ID").
	SSOURL("https://example.com/saml/sso/1234/").
	X509Certificates([]string{
		"-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----",
		"-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----",
	}).
	RPEntityID("RP_ENTITY_ID").
	CallbackURL("https://project-id.firebaseapp.com/__/auth/handler")
saml, err := client.CreateSAMLProviderConfig(ctx, newConfig)
if err != nil {
	log.Fatalf("error creating SAML provider: %v\n", err)
}

log.Printf("Created new SAML provider: %s", saml.ID)

Python

saml = auth.create_saml_provider_config(
    display_name='SAML provider name',
    enabled=True,
    provider_id='saml.myProvider',
    idp_entity_id='IDP_ENTITY_ID',
    sso_url='https://example.com/saml/sso/1234/',
    x509_certificates=[
        '-----BEGIN CERTIFICATE-----\nCERT1...\n-----END CERTIFICATE-----',
        '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
    ],
    rp_entity_id='P_ENTITY_ID',
    callback_url='https://project-id.firebaseapp.com/__/auth/handler')

print('Created new SAML provider:', saml.provider_id)

On completion, the method returns a SAMLAuthProviderConfig object for the newly created configuration.

Updating a SAML provider configuration

The following example demonstrates how to modify a SAML provider configuration. You can update any field, except for the provider ID.

Node.js

const updatedConfig = {
  x509Certificates: [
    '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
    '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
  ],
};
admin.auth().updateProviderConfig('saml.myProvider', updatedConfig).then(() => {
  // Successful update.
}).catch((error) => {
  // Handle error.
});

Go

updatedConfig := (&auth.SAMLProviderConfigToUpdate{}).
	X509Certificates([]string{
		"-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----",
		"-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----",
	})
saml, err := client.UpdateSAMLProviderConfig(ctx, "saml.myProvider", updatedConfig)
if err != nil {
	log.Fatalf("error updating SAML provider: %v\n", err)
}

log.Printf("Updated SAML provider: %s", saml.ID)

Python

saml = auth.update_saml_provider_config(
    'saml.myProvider',
    x509_certificates=[
        '-----BEGIN CERTIFICATE-----\nCERT2...\n-----END CERTIFICATE-----',
        '-----BEGIN CERTIFICATE-----\nCERT3...\n-----END CERTIFICATE-----',
    ])

print('Updated SAML provider:', saml.provider_id)

On completion, the method returns a SAMLAuthProviderConfig object for the updated configuration.

Getting a SAML provider configuration

The primary way to identify a SAML configuration is using its provider ID. The following example shows how to get a SAML provider configuration:

Node.js

admin.auth().getProviderConfig('saml.myProvider').then((config) => {
  // Get display name and whether it is enabled.
  console.log(config.displayName, config.enabled);
}).catch((error) => {
  // Handle error. Common error is that config is not found.
});

Go

saml, err := client.SAMLProviderConfig(ctx, "saml.myProvider")
if err != nil {
	log.Fatalf("error retrieving SAML provider: %v\n", err)
}

log.Printf("%s %t", saml.DisplayName, saml.Enabled)

Python

saml = auth.get_saml_provider_config('saml.myProvider')
print(saml.display_name, saml.enabled)

If a provider with the given ID exists, the method returns a SAMLAuthProviderConfig object.

Deleting a SAML provider configuration

The following example shows how to delete a SAML provider configuration:

Node.js

admin.auth().deleteProviderConfig('saml.myProvider').then(() => {
  // Successful deletion.
}).catch((error) => {
  // Handle error.
});

Go

if err := client.DeleteSAMLProviderConfig(ctx, "saml.myProvider"); err != nil {
	log.Fatalf("error deleting SAML provider: %v\n", err)
}

Python

auth.delete_saml_provider_config('saml.myProvider')

Listing SAML provider configurations

The following example shows how to list existing SAML provider configurations:

Node.js

// Returns 10 SAML provider configs starting from the specified nextPageToken offset.
admin.auth().listProviderConfigs({type: 'saml', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
  results.providerConfigs.forEach((config) => {
    console.log(config.providerId);
  });
  // To list the next 10:
  // return admin.auth().listProviderConfigs(
  //     {type: 'saml', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
  // Handle error.
});

Go

iter := client.SAMLProviderConfigs(ctx, "nextPageToken")
for {
	saml, err := iter.Next()
	if err == iterator.Done {
		break
	}
	if err != nil {
		log.Fatalf("error retrieving SAML providers: %v\n", err)
	}

	log.Printf("%s\n", saml.ID)
}

Python

for saml in auth.list_saml_provider_configs('nextPageToken').iterate_all():
    print(saml.provider_id)

Each batch of results contains a list of provider configurations, and a next page token used to fetch the next batch. When all providers have been listed, no token is returned.

By default, 100 providers are returned with each batch. This is also the maximum number of providers per batch.

Working with OIDC providers

Creating an OIDC provider configuration

You'll need to supply the following parameters when creating an OIDC provider configuration. You may need to consult your identity provider's documentation for details on how to obtain some of the values.

Display name
A user-friendly display name for the configuration. This name is also the provider label in the Cloud Console.
Enabled
Whether the current provider configuration is enabled or disabled. Users cannot sign in with disabled providers.
Provider ID
The provider's unique identifier, beginning with oidc..
Client ID
The ID used to confirm the audience of an OIDC provider's ID token.
Issuer
The provider issuer used to match the ID token and locate the OIDC discovery document at /.well-known/openid-configuration. The discovery document is needed to:
  • Verify the provided issuer.
  • Determine the authentication and authorization endpoints during the OAuth id_token flow.
  • Retrieve the public signing keys using jwks_uri to verify the OIDC provider's ID token's signature.
  • Determine the claims_supported to construct the user attributes to be returned in the additional user info response.
The ID token will be validated according to the OpenID Connect specification.

The following example demonstrates how to create an OIDC provider configuration:

Node.js

const newConfig = {
  displayName: 'OIDC provider name',
  enabled: true,
  clientId: 'CLIENT_ID2',
  issuer: 'https://oidc.com/CLIENT_ID2',
  providerId: 'oidc.provider2'
};
admin.auth().createProviderConfig(newConfig).then(() => {
  // Successful creation.
}).catch((error) => {
  // Handle error.
});

Go

newConfig := (&auth.OIDCProviderConfigToCreate{}).
	DisplayName("OIDC provider name").
	Enabled(true).
	ID("oidc.myProvider").
	ClientID("CLIENT_ID2").
	Issuer("https://oidc.com/CLIENT_ID2")
oidc, err := client.CreateOIDCProviderConfig(ctx, newConfig)
if err != nil {
	log.Fatalf("error creating OIDC provider: %v\n", err)
}

log.Printf("Created new OIDC provider: %s", oidc.ID)

Python

oidc = auth.create_oidc_provider_config(
    display_name='OIDC provider name',
    enabled=True,
    provider_id='oidc.myProvider',
    client_id='CLIENT_ID2',
    issuer='https://oidc.com/CLIENT_ID2')

print('Created new OIDC provider:', oidc.provider_id)

On completion, the method returns an OIDCAuthProviderConfig object for the newly created configuration.

Updating an OIDC provider configuration

The following example demonstrates how to modify an OIDC provider configuration. You can update any field, except for the provider ID.

Node.js

const updatedConfig = {
  displayName: 'OIDC provider name',
  enabled: true,
  clientId: 'CLIENT_ID',
  issuer: 'https://oidc.com/',
};
admin.auth().updateProviderConfig('oidc.myProvider', updatedConfig).then(() => {
  // Successful update.
}).catch((error) => {
  // Handle error.
});

Go

updatedConfig := (&auth.OIDCProviderConfigToUpdate{}).
	DisplayName("OIDC provider name").
	Enabled(true).
	ClientID("CLIENT_ID").
	Issuer("https://oidc.com")
oidc, err := client.UpdateOIDCProviderConfig(ctx, "oidc.myProvider", updatedConfig)
if err != nil {
	log.Fatalf("error updating OIDC provider: %v\n", err)
}

log.Printf("Updated OIDC provider: %s", oidc.ID)

Python

oidc = auth.update_oidc_provider_config(
    'oidc.myProvider',
    client_id='CLIENT_ID',
    issuer='https://oidc.com')

print('Updated OIDC provider:', oidc.provider_id)

On completion, the method returns an OIDCAuthProviderConfig object for the updated configuration.

Getting an OIDC provider configuration

The primary way to identify an OIDC configuration is using its provider ID. The following example shows how to get an OIDC provider configuration:

Node.js

admin.auth().getProviderConfig('oidc.myProvider').then((config) => {
  // Get display name and whether it is enabled.
  console.log(config.displayName, config.enabled);
}).catch((error) => {
  // Handle error. Common error is that config is not found.
});

Go

oidc, err := client.OIDCProviderConfig(ctx, "oidc.myProvider")
if err != nil {
	log.Fatalf("error retrieving OIDC provider: %v\n", err)
}

log.Printf("%s %t", oidc.DisplayName, oidc.Enabled)

Python

oidc = auth.get_oidc_provider_config('oidc.myProvider')

print(oidc.display_name, oidc.enabled)

If a provider with the given ID exists, the method returns an OIDCAuthProviderConfig object.

Deleting an OIDC provider configuration

The following example demonstrates how to delete an OIDC provider configuration:

Node.js

admin.auth().deleteProviderConfig('oidc.myProvider').then(() => {
  // Successful deletion.
}).catch((error) => {
  // Handle error.
});

Go

if err := client.DeleteOIDCProviderConfig(ctx, "oidc.myProvider"); err != nil {
	log.Fatalf("error deleting OIDC provider: %v\n", err)
}

Python

auth.delete_oidc_provider_config('oidc.myProvider')

Listing OIDC provider configurations

The following example shows how to list existing OIDC provider configurations:

Node.js

// Returns 10 OIDC provider configs starting from the specified nextPageToken offset.
admin.auth().listProviderConfigs({type: 'oidc', maxResults: 10, pageToken: 'nextPageToken'}).then((results) => {
  results.providerConfigs.forEach((config) => {
    console.log(config.providerId);
  });
  // To list the next 10:
  // return admin.auth().listProviderConfigs(
  //     {type: 'oidc', maxResults: 10, pageToken: results.pageToken});
}).catch((error) => {
  // Handle error.
});

Go

iter := client.OIDCProviderConfigs(ctx, "nextPageToken")
for {
	oidc, err := iter.Next()
	if err == iterator.Done {
		break
	}
	if err != nil {
		log.Fatalf("error retrieving OIDC providers: %v\n", err)
	}

	log.Printf("%s\n", oidc.ID)
}

Python

for oidc in auth.list_oidc_provider_configs('nextPageToken').iterate_all():
    print(oidc.provider_id)

Each batch of results contains a list of provider configurations, and a next page token used to fetch the next batch. When all providers have been listed, no token is returned.

By default, 100 providers are returned with each batch. This is also the maximum number of providers per batch.

What's next