Set up sign-in

Pick the ways people sign in to your app, send them back to the page that asked them to sign in, and choose where each role lands. Other apps in the same Firebase project can sign people in to the same accounts.

How each method works, what it stores and its limits are in Sign-in methods. This page is the app developer's setup.

Choose the methods

Everyone signs in on /signup, with one field for a phone number or an email address, and a Google button when Google is on. The page shows the app's own name, logo, words and colours: see Brand the sign-in page.

MethodDefaultNeeds
Email and passwordOnThe Email/Password provider on in the Firebase console. New accounts confirm their address with an emailed code.
Phone number (SMS code the first time, then a 6-digit PIN)OffThe sms feature on (it is unless src/custom/features.ts turns it off), and an SMS provider in Settings, SMS
GoogleOffThe Google provider turned on in the Firebase console
  1. In the Firebase console, Authentication, Sign-in method: make sure Email/Password is on, and enable Google if you want it.

  2. For email codes: keep the Debug Provider (Log Only) under Settings, Email Settings while you build: no email is sent, and the sign-up page shows the sign-up code, so an automated test can sign up without an inbox. Forgot password emails a reset code, which is then in Email Logs; to have the sign-in page show it, turn on Show password reset codes on screen beside the provider, and turn it off again when you are done. Switch to a real provider before launch. See Email engine.

  3. For phone: in the admin, open Settings, SMS. Keep the Test provider while you build: no SMS is sent, and the sign-up page shows the code. To test a PIN reset, turn on Show PIN reset codes on screen on the same page, and turn it off again when you are done. Switch to a real provider before launch. See SMS.

  4. Turn the methods on: Settings, User Settings, under Sign-in methods, switch on Phone number and Google as you want them. The Phone number switch only appears while the sms feature is on.

  5. Decide on sign-ups: "Enable User Signups" on the same page lets people create their own accounts. Turn it off for an invite-only app: admins then add people under Users, Add User.

Phone sign-in needs one Google Cloud permission on the functions' service account, or every phone sign-in fails after the code is accepted. See the trap in Sign-in methods.

Choose how strong passwords and PINs must be

By default new passwords and PINs must be hard to guess (the strict rule, see Passwords). A casual app, where a fancy password or PIN only gets in the way, can ask for less in src/custom/sign-in.ts:

import type { SignInChoice } from '../shared/utils/sign-in-strength';

export const CUSTOM_SIGN_IN: SignInChoice = {
    strength: 'simple',
};
Strict (empty, or 'strict')Simple ('simple')
New password8 characters or more; not one character repeated, a run, a common password, or the person's name or email6 characters or more
New PIN6 digits; not one digit repeated, a run like 123456, or a common patternAny 6 digits
The first admin (first-run wizard)StrictStrict
Your own PIN storesStrict, unless a store names a strengthSimple, unless a store names a strength (PINs for your app)
Wrong-try lockouts, rate limits, how PINs are keptThe same in both

It is a build-time choice: npm run dev and npm run build read it, and so does every functions build, through a copy scripts/arc-features.mjs writes to functions/src/sign-in.gen.ts. After changing it, deploy the website and the functions that set passwords and PINs; the deploy menu's "only the functions changed" choice finds them. A value other than 'strict' or 'simple' stops the build with what to write.

Only new passwords and PINs are checked, so changing the strength locks nobody out: a password or PIN set before still signs in, and the next new one meets the rule in force. The strength applies to admins too, since a password is chosen before anyone is made an admin; in a simple app, ask admins to sign in with Google.

In your members' language

The sign-in page, with its codes, PINs and error messages, follows the member language: the one chosen on this device, else the browser's when the app declares it. When the app declares member languages, a picker at the top right lets people choose, and the brand panel follows it too (see The sign-in page). The emails themselves are in English (see What stays in English). See Member languages for adding one, and for what stays in English.

Send people back where they were

A sign-in link can carry the page to return to: /signup?redirect=/learn. After signing in, the person goes to that page instead of their home page. Only a path on your own site is accepted: a full address, //host, or a sign-in page such as /signup is ignored, so a crafted link cannot send people elsewhere.

You rarely write the link yourself. Protect a page with userGuard and a signed-out visitor is sent to /signup?redirect= that page:

// src/custom/routes.ts
import type { Routes } from '@angular/router';
import { userGuard } from '../app/pages/user/user.guards';

export const CUSTOM_ROUTES: Routes = [
    { path: 'learn', canActivate: [userGuard], loadComponent: () => import('./pages/learn.page').then((m) => m.default) },
];

entitledGuard, from the same file, does the same for signed-out visitors and also sends signed-in people without a paid plan to /pricing. More on routes in Add pages and routes.

Set each role's home page

Without a redirect, people land on their role's home page: admins on /admin/dashboard, everyone else on /user/dashboard. Change it in src/custom/home.ts:

// src/custom/home.ts
import type { HomePages } from '../app/core/home/home';

export const CUSTOM_HOME: HomePages = {
    user: '/learn',
    '*': '/learn',
};

Keys are roles (admin, user, or your own); '*' is every role not listed. A role you list wins, then Arc CMS's default for that role, then your '*'.

'*' does not move admins: Arc CMS has its own home for admin, which comes before your '*'. To send admins elsewhere too, add an admin key.

To keep people on /user/dashboard but show your own page there, use src/custom/user-dashboard.ts instead: see Build the member area.

Sign in from another app

A mobile app, browser extension or second web app in the same Firebase project uses the same accounts. It signs in with the Firebase Auth SDK and calls Arc CMS's callables, which are all named arccms- followed by the function name. Every account must end with a token that carries arccms_uid (see Follow the account contract).

An existing account

MethodSteps
EmailFirebase signInWithEmailAndPassword. If the token has no arccms_uid, call arccms-refreshMyClaims with {} and refresh the token.
GoogleFirebase Google sign-in, then arccms-ensureGoogleAccount with {} (it creates the record on a first sign-in, when Google sign-in is on and sign-ups are open), then refresh the token. If the token still has no arccms_uid, call arccms-refreshMyClaims as for email.
Phonearccms-signInWithPin with { phone, pin } returns { token }; sign in with Firebase signInWithCustomToken.
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
import { getFunctions, httpsCallable } from 'firebase/functions';

const auth = getAuth(app);
const functions = getFunctions(app);

await signInWithEmailAndPassword(auth, email, password);
const { claims } = await auth.currentUser!.getIdTokenResult();
if (!claims['arccms_uid']) {
    await httpsCallable(functions, 'arccms-refreshMyClaims')({});
    await auth.currentUser!.getIdToken(true);
}

A login with no Arc CMS record gets an error from arccms-refreshMyClaims: treat it as "no access".

A new account by email

  1. arccms-requestSignupOtp with { email, name } emails a code.

  2. arccms-verifySignupOtp with { email, code } returns { verified, ticket }. Keep the ticket.

  3. Create the password login with Firebase createUserWithEmailAndPassword.

  4. arccms-createAccountRecord with { name, ticket } creates the record with the site's default role and sets the claims. It returns { id, created }. Refresh the token.

Send the ticket back from the same client that entered the code: it is what marks the address as verified on the record. New phone accounts go through arccms-requestPhoneOtp, arccms-verifyPhoneOtp and arccms-completePhoneSignup in the same way; the browser code in src/app/pages/(auth)/sign-in.service.ts shows every call and its input.

Every sign-up path refuses new accounts while "Enable User Signups" is off. An outside app then only signs in people who already have an account, such as those an admin adds under Users.