Single sign-on (SSO)
Single sign-on lets your team sign in through an identity provider (IdP) with one set of credentials instead of a LedgerBee password. LedgerBee supports OpenID Connect (OIDC): any provider that publishes a standard discovery document works, including Microsoft Entra ID and Okta.
Configure SSO under Settings → Workflows & access → Single sign-on. You must be an admin of the company.
Setup
Three steps, in order. Each one unlocks the next, so the page only ever shows you the step that is actually next.
- Verify an email domain. Publish a
TXTrecord to prove you control the domain your team's email addresses use. This is what lets LedgerBee route a sign-in to your provider. - Configure the connection. Register an OIDC application at your provider, then paste its issuer URL, client ID, and client secret into LedgerBee. A connection is set up ON a verified domain, so step 1 comes first.
- Save. LedgerBee reads your provider's metadata and presents your client credentials to it as part of saving. The connection goes live when the provider accepts them.
| Provider | Guide |
|---|---|
| Microsoft Entra ID | Set up SSO with Entra ID |
| Okta | Set up SSO with Okta |
| Any other OIDC provider | Set up SSO with any OIDC provider |
Verify domain ownership
A domain is the part of an email address after the @, such as acme.dk. A
company can verify several, each with its own connection and its own single
sign-on requirement. To retire one, remove it and add the replacement.
- Under Verified email domains, enter the domain and click Add domain. LedgerBee shows a record name and a unique value.
- Publish it at your DNS provider as a
TXTrecord. The host is_ledgerbee-ssoand the value looks likeledgerbee-sso-verification=93390ce0eae88e0196f4b62c8ff3bb4a. - Click Check now. The status moves from Awaiting DNS to Verified.
Enter the host as _ledgerbee-sso, without the domain. DNS providers append
their own zone to whatever you type in the name field, so a fully-qualified
value becomes _ledgerbee-sso.acme.dk.acme.dk and never resolves.
Only apex domains are accepted. acme.dk is valid; mail.acme.dk is not, which
is what keeps an address at a subdomain from matching a claim on the parent.
Public mailbox providers such as gmail.com are rejected.
Keep the record published
LedgerBee re-checks every verified domain daily. If the record disappears, the domain shows Record missing: everyone who already signs in keeps working, and linking a new person by their email address pauses until the record is back. Deleting the record does not lock your team out, and it does not leave LedgerBee trusting a domain you may no longer control.
The connection
Register the redirect URI shown on the page at your provider. Copy it with the Copy button rather than typing it — the token exchange sends the same value back to your provider, and the two must match byte-for-byte.
| Field | Value |
|---|---|
| Issuer URL | Your provider's OIDC issuer. LedgerBee fetches /.well-known/openid-configuration from it. Must be a public https URL. |
| Client ID | The client ID of the application you registered. |
| Client secret | Write-only. Stored encrypted and never shown again. |
| Subject claim | Which claim identifies the user. sub unless your provider documents otherwise. |
LedgerBee picks the client-authentication method from your provider's own
metadata — client_secret_post where it is offered, client_secret_basic
otherwise. There is nothing to configure.
The connection check
Saving runs the check. It fetches your provider's metadata, confirms the issuer it declares matches the one you entered, and then presents the client ID and secret to the token endpoint to confirm your provider accepts them — all in the same request, so what you see after saving is the outcome rather than a step still to take.
Passing both is what takes the connection live. Nothing else in the interface marks a connection live, and there is no field to declare one working — your provider has to answer for the credentials.
If the check does not pass, the connection is still saved: your credentials are not thrown away because a provider was unreachable. The status shows what happened, and Check again re-runs it once the provider side is fixed.
Changing the issuer, client ID, client secret, or subject claim takes the connection offline until it passes the check again. What the previous check proved no longer describes what is stored.
The check proves your provider accepts LedgerBee's credentials. It does not prove any particular person can sign in — that also depends on who your provider assigns to the application, and on the subject claim matching. A first sign-in is what confirms those.
How a member is matched
LedgerBee resolves an assertion to a user in this order and stops at the first match:
- A linked identity — someone who has signed in through this connection before, matched on the subject claim your provider sends.
- A provisioned user — with SCIM provisioning, a user your IdP already pushed, matched on external ID or work email.
- A verified email domain — the email address in the assertion, matched to an existing member, only when its domain is one you verified.
If none match, the sign-in is refused. An unknown person arriving from your provider is a membership decision, not an authentication one, so bring them in through SCIM or an invitation first.
Every match requires an active, accepted membership. A provider assertion proves who someone is; it never grants access on its own.
SSO enforcement
A live connection makes SSO possible. Enforcement decides who must use it, and it is set per verified domain, not for the company as a whole. Every domain in the table under Settings → Workflows & access → Single sign-on carries its own requirement: open the row's action menu, choose Configure enforcement, and set the Require single sign-on switch in the panel that opens. The panel is also where the reason for a refusal, and the sign-in that clears it, appear.
| State | Effect, for an address on that domain |
|---|---|
| Off | Any sign-in method works |
| Required | Only sign-in through that domain's connection reaches the company. Sessions signed in with a password, a passkey, or a personal Microsoft, Google or Apple account lose access. |
A member on an address you have not registered keeps every sign-in method.
The requirement belongs to the email domain rather than to the company, so an
external bookkeeper at bookkeeper.dk keeps signing in with a password while
everyone at acme.dk must come through your provider. Requiring a domain never
shuts out somebody that domain does not cover, which is what makes it safe to
require your own domain while people outside your directory still work in the
company.
It cuts the other way too: requiring one domain says nothing about a second one you also verified. Require each domain you want covered.
Sign in through the connection that domain points at to satisfy Required. A personal Microsoft sign-in does not satisfy it even from the same Entra directory, because it authenticates against a shared multi-tenant application that any directory can use.
Turning a requirement on ends the sessions it invalidates within minutes: the ones held by members on that domain, including your own if your address is on it, and no others.
The switch is unavailable while your own session would be one of them. Sign in through the provider first — the page offers a button — and it becomes available. Nothing blocks an administrator whose address is on a different domain.
Members who cannot enter still see the company in their company switcher, marked with the reason. Enforcement does not apply to advisor firms you have granted access; those are governed by the grant under Advisors.
What LedgerBee refuses
A domain can be required once both are true:
- The connection it points at has passed the connection check, and nothing has failed through it since.
- If your own address is on that domain, you signed in through it yourself.
Condition 2 applies only when you are one of the people the requirement would cover. An administrator whose address is on another domain — an external bookkeeper administering a client, say — can require a domain without signing in through it, which is the point: they hold no account in that directory and never will.
That also means requiring a domain no member of it has yet signed in through is allowed. If the provider accepts our credentials but admits nobody — the application is assigned to no users, or the subject claim is wrong — the people on that address are shut out until it is fixed. The blast radius is that one address at that one company; every other domain, and every member on one, is unaffected. If it happens, LedgerBee support can relax every requirement at the company — see Recover from an SSO lockout.
A requirement stays on through a provider outage. It is not relaxed when a DNS record lapses or a discovery lookup fails, and a company locked out that way is restored by LedgerBee support — see Recover from an SSO lockout.
What SSO does not do
It does not assign roles. LedgerBee reads no group or role claim from your provider. Permissions, admin rights, and company membership are set in LedgerBee, or synced with SCIM provisioning. Enabling SSO changes how someone signs in, not what they can do once they are in.
It does not remove existing sign-in methods. A member's password, passkey, and personal Microsoft, Google or Apple sign-in keep working. Those belong to the person across every company they work for, so one company's provider cannot reach them — which is also what leaves you a way in if the connection breaks. Requiring a domain stops those methods reaching THIS company for addresses on that domain; it does not delete them, and they still reach every other company the person belongs to.
If a step fails, see Troubleshoot SSO.