Skip to content

9. Microsoft 365 SSO (Cloudflare Access)

This is the security step. It makes the app require a Microsoft 365 sign-in (the same login as TOTLCOM email) before anyone can see it. It's done with Cloudflare Access, which is part of Cloudflare's free Zero Trust product.

There are three parts:

  1. Turn on Cloudflare Zero Trust (one-time).
  2. Register an app in Microsoft Entra ID (Azure AD) and connect it to Cloudflare as an "identity provider."
  3. Create an Access policy that protects oncall.totlcom.com and only allows your staff.

You'll need Microsoft admin rights

Registering the app in Microsoft Entra ID usually requires a Microsoft 365 / Entra administrator. If that's not you, do this part with whoever administers TOTLCOM's Microsoft tenant.


Part 1 — Turn on Cloudflare Zero Trust

  1. In the Cloudflare dashboard, click Zero Trust in the left sidebar.
  2. If it's your first time, you'll be asked to pick a team name (any short name, e.g. totlcom) and choose the Free plan. You may be asked for a payment card to verify, but the plan is free.
  3. Finish the wizard. You now have a Zero Trust dashboard.

Your team gets a sign-in domain like totlcom.cloudflareaccess.com — note it; you'll need it in Part 2.


Part 2 — Connect Microsoft 365 as the identity provider

2a. Register an application in Microsoft Entra ID

  1. Go to https://entra.microsoft.com (the Microsoft Entra admin center) and sign in as an admin.
  2. In the left menu: Identity → Applications → App registrationsNew registration.
  3. Name: Cloudflare Access (anything recognizable).
  4. Supported account types: choose Accounts in this organizational directory only (single tenant) — this restricts it to TOTLCOM.
  5. Redirect URI: choose platform Web and paste your Cloudflare callback URL:

    https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/callback
    

    Replace <your-team-name> with the team name from Part 1 (e.g. totlcom). 6. Click Register.

2b. Collect three values

On the app's Overview page, copy:

  • Application (client) ID
  • Directory (tenant) ID

Then create a secret:

  1. Go to Certificates & secrets → Client secrets → New client secret.
  2. Add a description and an expiry (e.g. 24 months), click Add.
  3. Copy the secret's Value immediately (not the "Secret ID"). You can't see it again later.

Treat the client secret like a password

Don't paste it into chat, email, or the code repo. You'll enter it only into Cloudflare in the next step. Set a calendar reminder before its expiry date — when it expires, sign-in breaks until you create a new one and update Cloudflare.

2c. Grant the permissions Cloudflare needs

  1. In the app registration: API permissions → Add a permission → Microsoft Graph → Delegated permissions.
  2. Add: openid, email, profile, and User.Read. (Add GroupMember.Read.All as well only if you plan to allow access by Microsoft 365 group later — optional.)
  3. Click Grant admin consent for TOTLCOM and confirm.

2d. Add Microsoft as an identity provider in Cloudflare

  1. In Zero Trust → Settings → Authentication → Login methods, click Add new.
  2. Choose Azure AD (Microsoft Entra ID).
  3. Fill in:
    • Name: Microsoft 365
    • App ID: the Application (client) ID from 2b
    • Client secret: the secret Value from 2b
    • Directory (tenant) ID: the Directory (tenant) ID from 2b
  4. (Optional) enable support groups if you added GroupMember.Read.All and want group-based rules.
  5. Click Save, then click Test on the new provider. A Microsoft login should pop up and report success.

Part 3 — Protect the app with an Access policy

3a. Create the application in Access

  1. In Zero Trust → Access → Applications, click Add an applicationSelf-hosted.
  2. Application name: On-Call Scheduler.
  3. Session duration: pick how long a sign-in lasts before re-auth (e.g. 24 hours or 1 week).
  4. Under Application domain, enter:
    • Subdomain: oncall
    • Domain: totlcom.com (so the full domain is oncall.totlcom.com).
  5. Under Identity providers, make sure Microsoft 365 is enabled (and turn off "Accept all available identity providers" if you only want Microsoft).
  6. Click Next.

3b. Add the allow rule

Now decide who may sign in. Create a policy:

  • Policy name: TOTLCOM staff
  • Action: Allow
  • Include — choose one approach:
    • Emails ending in @totlcom.com — simplest: everyone with a TOTLCOM mailbox can sign in. (Recommended to start.)
    • or Emails — list specific addresses for tighter control.
    • or Azure groups — a Microsoft 365 group (requires the optional group permission from 2c).

Click Next, leave the defaults on the last screen, and Add application.

Two layers of control — don't confuse them

  • Cloudflare Access (this page) decides who can sign in at all.
  • The app's Admin tab decides what a signed-in person can do (viewer/editor/admin).

Letting all @totlcom.com users sign in is fine: by default they're viewers until an admin promotes them. The very first admin comes from ADMIN_EMAILS (step 6).


How the app reads who you are

Once Access is in front, every request to the app carries the signed-in identity. The app reads the user's verified email from the Cloudflare Access token and uses it to decide their role. You don't configure anything else for this — it just works once the policy above is active.

Confirm it's working

  1. Open https://oncall.totlcom.com in a private/incognito window.
  2. You should be redirected to Microsoft sign-in. Sign in with a TOTLCOM account.
  3. You land in the app.
  4. Visit https://oncall.totlcom.com/api/v1/me — it should show your email and role (the first admin should see admin). This is the quickest way to confirm identity is flowing through correctly.

Built-in diagnostics

/(api/v1)/me returns your resolved email and role. If it shows unknown or the wrong role, see Troubleshooting.

Removing someone's access

To stop a person reaching the app entirely, remove them from the Access policy (or from the Microsoft group / email list it allows). To merely take away their editing rights but keep them able to view, change their role in the app's Admin tab instead.

Deploying updates