Guide 07 · Developer docs

Members, accounts and gated content

Building a member area on Core dna: who a member is in the data, the sign-in flows and their templates, single sign-on and passkeys, the my-account routing convention, members-only content, sessions and the page cache, and the security checks to run before launch.

L2
Unit 03 · Authenticators, SSO and linked accounts

Enabling a provider

Switching on Google, Microsoft or Facebook sign-in: the client to create at the provider, the redirect URIs to register for every hostname and environment, the order to fill in the settings, and the sign-in buttons the template draws from what is enabled.

Who this is for. The developer setting up provider sign-in on a site. Afterwards the provider works on every hostname the site answers on, development included, and the buttons follow what is switched on.

The steps

  1. Create a client at the provider: an OAuth client in Google Cloud, an app registration in Microsoft Entra ID, or a Facebook app. Note its id and secret.
  2. Register the redirect URIs with the provider, one for every hostname members will sign in on (below).
  3. Fill in the credentials on the admin's OAuth configuration screen, on its Configuration tab: Client ID, Client secret, and for Microsoft the Tenant.
  4. Then switch Enable on. Fill in the id and secret, and for Microsoft the Tenant, before switching it on, so the sign-in button works from the first test.
  5. Test it signed out, in a private window, on each hostname.

Set Forbid Backend Login on a provider meant only for members, so it cannot be used to sign in to the admin.

Redirect URIs

After the person signs in, the provider sends them back to the site's callback for that provider:

https://<hostname>/oauth/callback/<provider>, for example https://www.example.com/oauth/callback/google.

The platform builds it from the hostname the visitor is on at that moment. The provider accepts only redirect URIs registered with it, so register one for every hostname members can sign in from: the production domain, each alias domain, and every staging and development hostname. A missing one fails at the provider, with its own redirect URI error, before the site is involved, which is why the fault is often first seen on a new environment or a newly added domain.

The configuration screen's OAuth App Setup tab lists the exact URI for every hostname of every environment of the site, for each provider. Copy the list from there rather than typing it, and check it again whenever a hostname is added.

Development and production can share one client at the provider with all the URIs registered, or use separate clients; either way, a development client must never be the only one registered for production hostnames. Some providers also require the app to be published or verified before people outside the developer's organisation can use it: check the provider's console before launch.

Sign-in buttons

The sign-in page receives enabledOAuthAuthenticators: the enabled providers, as slug and display name, without passwords and passkeys. It includes the Core dna provider, which is on by default, so skip it on member pages. Loop the list rather than writing buttons by hand, so a provider switched off later disappears instead of leaving a button that answers 404:

Template code In templates/users/login.html
{foreach $enabledOAuthAuthenticators as $slug => $label}
  {if $slug != 'coredna'}
    <form method="post" action="{$_url->getFrontendPath('OAuth', 'loginWith', ['provider' => $slug])}">
      {$next = $_request->getParameter('redirectUrl')}
      {if $next}<input type="hidden" name="redirectUrl" value="{$next|escape}">{/if}
      <button>Sign in with {$label|escape}</button>
    </form>
  {/if}
{/foreach}
{% for slug, label in enabledOAuthAuthenticators %}
  {% if slug != 'coredna' %}
    <form method="post" action="{{ _url.getFrontendPath('OAuth', 'loginWith', {'provider': slug}) }}">
      {% set next = _request.getParameter('redirectUrl') %}
      {% if next %}<input type="hidden" name="redirectUrl" value="{{ next|e }}">{% endif %}
      <button>Sign in with {{ label|e }}</button>
    </form>
  {% endif %}
{% endfor %}

A plain link to /oauth/login-with/google works too. The form is there to carry redirectUrl, so a member sent to sign in from a members-only page comes back to it after the provider (Where the member lands). Put the Twig filter inside the loop as an if, as above: the for … if form of older Twig examples is a syntax error in the Twig version the platform runs.

What happens after the button is pressed, and the errors a member can meet, are in The sign-in handshake.

Go deeper

Was this page helpful?

Your answer goes to the docs team.