OpenID Connect and SAML Sign-In

Besides Microsoft, Google and Facebook, a portal can sign people in through any OpenID Connect or SAML 2.0 identity provider: Okta, Auth0, Microsoft Entra External ID, a customer's or partner's own Entra tenant, AD FS, Ping, Google Workspace. Each provider you configure is a button on the sign-in page, and needs no code.

A sign-in through one of these providers is matched, linked or signed up as a contact exactly as a Microsoft or Google sign-in is. Internal users (system users) sign in with Microsoft — see Entra ID Sign-In Setup.

Turn it on

Projects created from the templates for external users already have this in Program.cs. It reads every provider configured under Authentication:OpenIdConnect and Authentication:Saml2, and adds none until one is configured:

SAML comes from the PowerPortalsPro.Identity.Saml2 package, which those projects reference. A project created before this feature needs the call and the package added.

Addresses to register with the provider

Each provider has a name — the key of its configuration section, ContosoOkta in the examples below — and the addresses the provider sends people back to are made from it in lower case. Register them exactly, once for each host the portal runs on.

What Address
OpenID Connect redirect URI https://your-portal.example.com/signin-{name}
SAML assertion consumer service (HTTP-POST) https://your-portal.example.com/saml2/{name}/acs
SAML entity ID (audience) https://your-portal.example.com/saml2/{name}
The portal's SAML metadata https://your-portal.example.com/saml2/{name}/metadata

The addresses are the same in every language. A sign-in started on a page in another language — /es/… — comes back through the site's own address and then to the page it started on, in that language.

OpenID Connect providers

Add a section for each provider under Authentication:OpenIdConnect. Keep the client secret in user secrets locally and in Key Vault once deployed.

Setting What it is
DisplayNameThe name on the sign-in button. Defaults to the provider's name.
AuthorityThe provider's issuer — the address its /.well-known/openid-configuration is under. Required unless MetadataAddress is given.
MetadataAddressThe discovery document's own address, for a provider that publishes it somewhere else.
ClientId, ClientSecretThe portal's client id and secret at the provider. Required.
ScopesScopes to ask for besides openid, profile and email, which are always asked for.
CallbackPathThe redirect URI's path, when /signin-{name} won't do.
TrustedEmailDomainsThe email domains this provider is trusted for — see Which addresses are trusted below. Empty by default. In an App Service setting, write it comma-separated.
GetClaimsFromUserInfoEndpointWhether to read the profile from the provider's user info endpoint as well as the ID token. On by default, since some providers put no email in the ID token.

The portal uses the authorization code flow with PKCE, signs in through Identity's external cookie, and keeps no tokens. It reads the person's id from sub, and their address and name from email, given_name and family_name.

Okta (OpenID Connect)

  1. Create an app integration: OIDC - OpenID Connect, of type Web Application, with the Authorization Code grant.
  2. Add the portal's redirect URI as a Sign-in redirect URI, assign the people or groups who may sign in, and copy the client id and secret.
  3. The authority is your authorization server's issuer, e.g. https://contoso.okta.com/oauth2/default.

Auth0

  1. Create an application of type Regular Web Application.
  2. Add the portal's redirect URI to Allowed Callback URLs, and copy the client id and secret.
  3. The authority is your tenant's domain, e.g. https://contoso.us.auth0.com/, or your custom domain.

Microsoft Entra External ID

  1. In the external tenant, register an application with the portal's redirect URI as a Web redirect URI, and add a client secret.
  2. Create a sign-up and sign-in user flow and add the application to it.
  3. The authority is https://<tenant subdomain>.ciamlogin.com/<tenant id>/v2.0. When the user flow verifies each address before an account is created — email with password and email one-time passcode both do — this is an identity provider you run for your own customers, and TrustedEmailDomains can be *.

A customer's or partner's Entra tenant

For an organization whose people should sign in with their own work accounts, without the multi-tenant Microsoft button:

  1. In their tenant, register a single tenant application with the portal's redirect URI as a Web redirect URI, and add a client secret.
  2. The authority is https://login.microsoftonline.com/<their tenant id>/v2.0.
  3. List their domains in TrustedEmailDomains; an address anywhere else is confirmed by email first. Their tenant's id reaches the session, as it does for the Microsoft button. Entra's own verification claims (xms_edov, verified_primary_email) aren't taken from a provider: the tenant behind it administers the claims it sends.

SAML 2.0 providers

Add a section for each provider under Authentication:Saml2. The provider's metadata gives the portal its sign-on address and the certificates its responses are signed with; it is read again every day, so a certificate the provider rolls over is picked up.

Setting What it is
DisplayNameThe name on the sign-in button. Defaults to the provider's name.
MetadataAddressThe address of the identity provider's metadata. Required, and must be https.
IdentityProviderEntityIdThe identity provider's entity ID, which responses must be issued by. Defaults to the one its metadata names.
EntityIdThe portal's own entity ID. Defaults to https://{host}/saml2/{name} on whatever host the request came to; set it when the portal answers on more than one host, so they share one registration at the provider.
CallbackPath, MetadataPathThe assertion consumer service's and metadata's paths, when /saml2/{name}/acs and /saml2/{name}/metadata won't do.
TrustedEmailDomainsThe email domains this provider is trusted for — see Which addresses are trusted below. Empty by default. In an App Service setting, write it comma-separated.
AllowIdentityProviderInitiatedAccepts sign-ins the provider starts — someone opening the portal from a tile on their provider's dashboard. Off by default. They go on to the portal's external-login page, and then to a local page named by the RelayState (/orders or ReturnUrl=/orders). Each response is accepted once per server.
RequireHttpsMetadataWhether MetadataAddress must be https. On by default; turn it off only to try a provider running on your own machine.

Responses must be signed by a certificate in the provider's metadata, issued by its entity ID, for the portal's entity ID, sent to the assertion consumer service, and in answer to the request the same browser made. The NameID identifies the account, so it must be persistent or the email address; a transient one is refused. The address and name are read from the attributes providers commonly use: email, mail, emailaddress and the WS-Federation claim names, and givenName or firstName and surname or lastName.

Microsoft Entra ID (enterprise application)

  1. Create an enterprise application, Integrate any other application you don't find in the gallery, and choose SAML single sign-on.
  2. Set Identifier (Entity ID) to the portal's entity ID and Reply URL to its assertion consumer service.
  3. Copy the App Federation Metadata Url into MetadataAddress, and assign the users or groups who may sign in.

Okta (SAML)

  1. Create an app integration of type SAML 2.0.
  2. Set Single sign-on URL to the assertion consumer service and Audience URI (SP Entity ID) to the portal's entity ID; choose a Persistent or EmailAddress name ID format, and add email, firstName and lastName attribute statements.
  3. Copy the application's Metadata URL into MetadataAddress.

AD FS

  1. Add a relying party trust, importing the portal's metadata from its address.
  2. Add claim issuance rules that send the email address, given name and surname, and a persistent name ID.
  3. MetadataAddress is https://<your AD FS host>/FederationMetadata/2007-06/FederationMetadata.xml.

Signed requests and encrypted assertions

Most providers need neither. For one that requires signed authentication requests or encrypts its assertions, add the provider in code with the certificates; both are published in the portal's metadata for the provider to import.

Which addresses are trusted

A sign-in whose address the portal trusts goes straight into the contact that has it, and a new account starts with that address confirmed. Any other address is confirmed by email first, once; after that the link between the sign-in and the contact is what finds it.

Important

* trusts every address the provider asserts. Use it only for an identity provider you run for your own users and which verifies addresses before asserting them. Never use it for a provider a customer or partner administers: anyone who administers it can create an account with any address, including one belonging to another organization's contact, and would sign in as that contact.

Sign-in buttons

Every provider is a button on the sign-in page, labeled with its display name. Four more settings in a provider's section change how its button looks and where it sits:

Setting What it is
IconA small logo shown before the name in the standard button — a customer's own logo on their sign-in, say.
ButtonImageAn image shown instead of the standard button: a provider's own “Sign in with …” button.
ButtonImageDarkThe same image for the dark theme. Without it, ButtonImage is used in both.
OrderWhere the button sits: lower comes first, and buttons with the same order keep the order their providers were added in. 0 by default.

An image is a path from the site's root — a file in the portal's wwwroot, such as /images/contoso-logo.svg — or an https address. A path is served from the site's root on every page, in every language. Anything else stops the portal at startup, naming the setting.

Any other provider's button, Microsoft's and Google's included, is changed in code:

Microsoft, Google and Facebook show their own “Sign in with …” buttons, in light and dark versions, unless you set one of these for them.

Troubleshooting