An identity provider is the dependency every other service shares and none of them report on. When Keycloak or authentik goes down, your wiki, your Grafana, your Git forge, and your internal tools all stay up, return 200 to a monitor, and refuse to let anyone in. Our guide to monitoring OAuth and OpenID providers covers the protocol-level checks that apply to any IdP, hosted or not: discovery document, JWKS, callback. This one is about what is different when you run the IdP yourself: health endpoints that live on ports you must not expose, background workers that fail silently, outposts that sit between users and apps, and databases that only you are backing up.

Both products get the same four layers: an external monitor on something that proves the server is serving, an assertion that catches a half-broken state, a heartbeat for the parts that cannot be seen from outside, and the certificate. Keycloak first.

Keycloak

Where the health endpoints are, and why you probably cannot use them

Keycloak has four health endpoints, /health, /health/live, /health/ready, and /health/started, and they come with two conditions. First, they only exist if the server was built with --health-enabled=true. Second, since Keycloak 25 they are served by default on the management interface, port 9000, not on the port your users reach. The documented probe is curl --head -fsS http://localhost:9000/health/ready. You can move them back onto the main port by setting http-management-health-enabled=false, and the documentation's advice if you do is to block /health at your reverse proxy. Either way, the message is the same: these endpoints are for Kubernetes probes and internal tooling, and they should not be reachable from the internet.

Two consequences for external monitoring. You will usually be checking something else, and the thing that checks the database directly (/health/ready) stays inside the network, where you reach it with a heartbeat rather than an HTTP monitor.

What to monitor from outside

Three unauthenticated URLs on the public port tell you most of what you need:

  1. The realm endpoint. GET https://sso.example.com/realms/<realm> returns a small JSON document with "realm":"<realm>", the realm's public key, and the token and account service URLs. A 200 means Keycloak is up and that realm exists; a 404 means someone deleted or renamed it. This is the primary monitor. On the free plan, expected status 200 is the whole configuration; on Pro, add the assertion contains "realm":"<realm>" so a proxy serving a 200 error page cannot pass.
  2. The discovery document. /realms/<realm>/.well-known/openid-configuration is what every client library fetches to find the endpoints. Pro assertion: contains "issuer":"https://sso.example.com/realms/<realm>", with your exact hostname. This catches the classic self-hosted mistake where KC_HOSTNAME (or a proxy header) is wrong and the issuer comes back as an internal name, which makes every client reject every token even though the server is "up".
  3. The JWKS. /realms/<realm>/protocol/openid-connect/certs returns {"keys":[...]}. Applications validate token signatures against it, often on every request; if it is unreachable, sessions start dying as caches expire. Pro assertion: contains "keys", or the regex "kid":" to require at least one key.

If you want to prove the login page itself renders, point a monitor at the authorization endpoint with a real client: /realms/<realm>/protocol/openid-connect/auth?client_id=<public-client>&response_type=code&redirect_uri=<a registered URI>&scope=openid. Keycloak returns the login form with a 200; with a missing or unregistered parameter it returns a 400 error page instead, so a wrong redirect URI fails the monitor, which is the behavior you want. Use a Pro keyword from the form (the default theme's login form has the id kc-form-login; a custom theme will differ). Do not go further than rendering the form: scripted logins create sessions and events on every check.

The admin console (/admin/master/console/) is a single-page app that returns 200 even when the backend is sick, and it is the one path you should restrict at the proxy anyway. If you do restrict it, add an inverse monitor expecting the proxy's 403, as described in the custom-headers guide, so you are told if the restriction ever disappears.

The cache problem, and the readiness heartbeat

Keycloak caches realms, clients, and keys in Infinispan. After the database goes away, /realms/<realm>, the discovery document, and the JWKS can keep answering from cache for some time, while anything that writes, which is every login and every token refresh, fails. Your external monitors stay green while your users are locked out. /health/ready is the endpoint that checks the database, and it is on the management port.

So bring it to CronAlert the other way round. On any machine in the same network (or in a sidecar), run a cron job that probes readiness and pings a heartbeat monitor only on success:

# every minute; the Keycloak container image has no curl, so run this from the host or another container
* * * * * curl --head -fsS --max-time 5 http://keycloak:9000/health/ready >/dev/null && curl -fsS --max-time 10 https://cronalert.com/api/heartbeat/YOUR-TOKEN

Heartbeat interval 1 minute, grace 3 to 5 minutes. A database outage now produces an alert within a few minutes even while the cached public endpoints look fine. If https-client-auth is set to required, the management interface inherits it; set https-management-client-auth to request or none, as the docs suggest, so the probe does not need a client certificate. Heartbeat monitors are a Pro feature; sizing the grace period explains the numbers.

Clustering and the load balancer

With several Keycloak nodes behind a load balancer, the external monitors see the balancer's view, which is right for "can users log in", and wrong for "is node 2 healthy". The readiness heartbeat above is per node (one cron line per node, one heartbeat each), which tells you a node dropped out of a cluster that is still serving. Sticky sessions matter less than they used to, but if you use them, a monitor that lands on one dead node and fails while users on other nodes are fine is a real possibility; multi-region checks with a majority threshold help here.

Authentik

Health endpoints you can actually reach

authentik is easier from outside. The server answers GET /-/health/live/ with 200 as long as the process is running, and GET /-/health/ready/ with 200 when it can establish a PostgreSQL connection (older versions also required Redis; check your version's docs). Both are on the main port, both are unauthenticated, and the official Docker Compose and Helm deployments use them as probes. Create two HTTP monitors:

  • https://auth.example.com/-/health/ready/, expected 200, timeout 10 seconds. This is the primary monitor: a 503 or timeout means the database is gone or the server is not accepting connections, which is a login outage.
  • https://auth.example.com/-/health/live/, expected 200. Separately useful because live green with ready red is a database problem, while both red is the server, the proxy, or the host.

Add the discovery document for any OIDC provider you care about, /application/o/<provider-slug>/.well-known/openid-configuration, with the same issuer assertion used for Keycloak above; a wrong AUTHENTIK_HOST or external host setting shows up there first. And unless you have reason not to, restrict /-/health/ at your proxy to monitoring and probe sources only; it leaks nothing sensitive, but there is no need to advertise it.

The worker

authentik's worker runs everything that is not a request: outpost synchronisation, LDAP and SCIM sources, token and session cleanup, email, blueprints. When it dies, nothing visible breaks immediately; logins keep working from the server process, and the damage shows up hours later as expired certificates that did not renew, a directory sync that never ran, or an outpost whose config is stale. The worker has no public endpoint. The documented check is ak healthcheck inside the worker container (it also serves /-/health/ready/ on its own listen port, internally).

# every 5 minutes on the Docker host
*/5 * * * * docker exec authentik-worker-1 ak healthcheck && curl -fsS --max-time 10 https://cronalert.com/api/heartbeat/YOUR-TOKEN

Heartbeat interval 5 minutes, grace 10. On Kubernetes, a CronJob that runs the same command against the worker service, or simply a check that the worker Deployment has ready replicas, feeds the same heartbeat; Kubernetes CronJob monitoring has the template.

Outposts

Outposts are the proxy, LDAP, RADIUS, and RAC components that sit in front of applications or speak other protocols. Each exposes /outpost.goauthentik.io/ping on its metrics port 9300, which is internal. From outside, the useful test is the thing the outpost is for:

  • Proxy outposts. A monitor on the protected application, https://grafana.example.com/ say, gets redirected to authentik's login flow. CronAlert's HTTP checks follow redirects, so the monitor lands on the flow page with a 200; on Pro, assert a keyword from that page (the word authentik appears in the default flow interface's title) so you know the redirect went to authentik and not to an error page. This single monitor proves the outpost, its connection to the server, and the server itself. A redirect loop or a 502 from the outpost fails it. Remember the trap described in reverse proxy monitoring: without the keyword, any page that eventually returns 200 passes.
  • LDAP outposts. Use a TCP monitor on the LDAP port (389 or 636 as you have configured it) if it is exposed to the monitoring network; otherwise an ldapsearch in a cron job with a heartbeat, which also verifies a bind.
  • Embedded outpost. Runs inside the server process, so the server's /-/health/ready/ covers it.

Both: certificates and backups

Every HTTP monitor on every plan watches the certificate of the hostname it checks, so the realm or readiness monitor already alerts before sso.example.com expires. If clients also use a separate admin or account hostname, monitor it too; a dead certificate on an IdP is a total outage with a browser warning as its only error message. See SSL certificate monitoring.

The database behind either product is the thing you cannot recreate: every user, credential, client secret, and signing key is in it. A nightly pg_dump (Keycloak also supports MariaDB, MySQL, and Oracle; authentik is PostgreSQL only) with a heartbeat ping at the end, interval 1 day, grace a few hours, is the minimum; monitoring database backups covers the restore test. For authentik, blueprints and the media directory (custom icons, flow backgrounds) belong in the same job.

Reading an alert

AlertLikely causeFirst thing to check
Keycloak realm endpoint timeout or 502Proxy, host, or Keycloak processContainer or pod status; proxy logs
Realm endpoint 404Realm renamed or deleted, or wrong http-relative-path after an upgradeAdmin console realm list; KC_HTTP_RELATIVE_PATH
Discovery issuer assertion failsKC_HOSTNAME or proxy headers wrong after a changeThe issuer value in the body
Public endpoints green, readiness heartbeat overdueDatabase unreachable; endpoints served from cacheDatabase; connection pool errors in Keycloak logs
authentik live green, ready 503PostgreSQL (or Redis on older versions) unreachableDatabase container; AUTHENTIK_POSTGRESQL__*
authentik worker heartbeat overdueWorker container stopped or crash-loopingdocker logs on the worker; memory
Protected-app monitor fails, authentik itself greenProxy outpost down, lost its token, or redirect loopOutpost logs; Outposts page health in the admin UI
Certificate alertRenewal stoppedProxy's ACME logs; renewal monitoring

Frequently asked questions

Should I just expose Keycloak's management port to CronAlert?

No. There are no fixed probe IP ranges to allowlist, and the management interface also serves metrics. Keep it internal and use the heartbeat.

How often should the IdP be checked?

The interval is set by plan: every 3 minutes on Free, every minute on Pro. Discovery and JWKS requests are cheap and cached by Keycloak and authentik alike; a one-minute check is far below what a single busy application generates.

Can one monitor cover both the IdP and an app behind it?

The proxy-outpost monitor above does, for authentik. For Keycloak-protected apps using an OIDC library, the app typically shows its own login button rather than redirecting, so monitor the IdP endpoints directly and the app separately; monitoring internal tools covers the app side.

What about the authentik admin interface?

/if/admin/ requires a session and redirects to the login flow, so a monitor on it tests the same thing as the flow page. Prefer the readiness endpoint and, if you restrict the admin path at the proxy, an inverse monitor expecting the refusal.

Is any of this on a paid plan?

The status-only monitors on the realm, discovery, JWKS, and authentik health endpoints, plus certificate monitoring, are free. Keyword assertions, heartbeats (readiness, worker, backups), and TCP monitors for LDAP are Pro at $5/month.

Get started

Two or three public URLs with the right assertions, a heartbeat for what the network hides, and the certificate, and your identity provider stops being the outage nobody's monitor reports. Create a free CronAlert account and add the realm or readiness monitor first. Related reading: monitoring OAuth and OpenID providers, monitoring Docker self-hosted services, Kubernetes uptime monitoring, monitoring self-hosted GitLab, and monitoring multi-tenant SaaS.