Authentication¶
The ntfy engine supports three first-class authentication modes for the outbound publish request,
modeled by AuthMode, a sealed type with three variants: BearerToken, BasicAuth, and None.
Which variant is active is derived automatically from which of token / username / password you
configure — there is no separate "auth mode" switch. This is engine-wide: it applies identically
whether you configure via env/sysprop/ntfy.properties, Logback XML, the Log4j2 <Ntfy> attributes,
Spring ntfy.*, or Quarkus quarkus.ntfy.*. (For the full list of where each key lives, see
configuration.md.)
The three modes¶
BearerToken¶
Set token. The request is sent with an Authorization: Bearer <token> header. This is the
recommended mode for a private ntfy topic protected by an access token.
# Spring application.yml
ntfy:
url: https://ntfy.example.com
topic: my-app-alerts
token: tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Quarkus application.properties
quarkus.ntfy.url=https://ntfy.example.com
quarkus.ntfy.topic=my-app-alerts
quarkus.ntfy.token=tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
<!-- Log4j2 log4j2.xml -->
<Ntfy name="ntfy" url="https://ntfy.example.com" topic="my-app-alerts"
token="tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
# Core / plain Logback / plain Log4j2 via environment
export NTFY_URL=https://ntfy.example.com NTFY_TOPIC=my-app-alerts
export NTFY_TOKEN=tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
BasicAuth¶
Set both username and password. The request uses HTTP Basic authentication. Use this when the
ntfy server (or a reverse proxy in front of it) is gated by a username/password pair rather than a
token.
Both username and password must be non-blank. If only one of the two is set, the pair is
ignored and the engine falls back to None mode: every publish goes out with no
Authorization header. The engine emits a one-time startup warning for this half-configured state
(username or password set but not both — basic auth is incomplete; publishing WITHOUT an Authorization header) —
unless a token is also configured, in which case the token supersedes
basic auth entirely and only the token-plus-basic overlap warning below can apply. Activation
still proceeds. Against a protected server the observable
symptom is ntfy publish failed for topic '<topic>' (HTTP 401) (or 403) diagnostics — see
troubleshooting.md. Against a permissive server the publishes may even
succeed, unauthenticated, while you believe auth is in effect. If Basic Auth appears not to apply,
first check that both values are actually set and non-blank (a ${VAR} that resolves to an empty
string counts as blank).
Verifying credentials at startup¶
Every credential problem above shares the same failure mode: nothing looks wrong until the first real error alert fails to deliver, which is the worst possible moment to discover a revoked token. The opt-in startup self-test closes that gap by making one round-trip at boot and reporting the result:
A revoked, expired or insufficiently-scoped credential then surfaces immediately as
ntfy startup self-test FAILED (HTTP 401) — the server rejected the credentials; the token may be
revoked or expired, or it may not grant access to this topic.
Prefer publish over probe when it is credentials you want to verify. ntfy grants read and write
permissions separately, so probe — a read-only request — is passed by a read-only token that would
still fail every real alert, and on an open server anonymous reads make it prove nothing at all. No
self-test diagnostic ever echoes the token, username or password.
None¶
Set neither token nor username/password. Publishes go out with no Authorization header at
all. None is a valid, first-class configuration — not a misconfiguration — and is the correct mode
for a public ntfy.sh topic or a self-hosted server whose publish endpoint is deliberately open.
Precedence: token wins over Basic Auth¶
If you configure both a token and a username/password pair, the engine does not fail and
does not refuse to start. Instead:
BearerTokentakes precedence — every request uses the token, and the configuredusername/passwordare ignored for theAuthorizationheader.- A one-time warning is emitted at startup:
both token and username/password configured — token takes precedence. - Startup still proceeds and alerting still activates normally. Authentication configuration is never a reason to block activation.
This lets you leave stale username/password values in place (for example while migrating from
Basic Auth to a token) without breaking anything — the token simply wins, and the one-time warning
tells you the overlap exists so you can clean it up.
Credentials over plain http://¶
If credentials would traverse a cleartext http:// endpoint, the Authorization header (or the
URL's embedded userinfo) and every alert body are readable by any on-path observer. The engine
detects this at startup for a configured token, a username/password pair, or userinfo
embedded in the URL itself (http://user:pass@host — flagged even when no separate credential is
configured).
By default (since 2.0, require-https-for-credentials = true) this is a hard failure: the engine
refuses activation, emitting a fixed, credential-safe diagnostic, so a secret never traverses the
network unencrypted. A credential-free http:// endpoint is unaffected.
For a deliberate self-hosted plain-HTTP setup, set require-https-for-credentials = false to
restore the pre-2.0 warn-and-activate behavior: the engine then emits a one-time warning —
credentials configured with a plain http:// URL — the token/password and alert content are sent unencrypted; use https:// —
but still activates. The key is available on every configuration surface: Logback XML
<requireHttpsForCredentials>, Log4j2 <Ntfy requireHttpsForCredentials="false">,
Spring ntfy.require-https-for-credentials, Quarkus
quarkus.ntfy.require-https-for-credentials, env NTFY_REQUIRE_HTTPS_FOR_CREDENTIALS, sysprop
ntfy.require-https-for-credentials, or NtfyConfig.Builder.requireHttpsForCredentials(false) for
programmatic core users.
The token is never surfaced in diagnostics¶
The engine's self-diagnostics (its ACTIVE line, publish-failure warnings, error messages) never
include the token, username, or password value. The only credential-adjacent information that
can appear is the url and topic — and even then, if you supply a URL with embedded userinfo
(https://user:pass@host/…), the userinfo is stripped before the URL is logged. No diagnostic
output ever echoes a secret. Where those diagnostics appear differs per framework (Logback's
StatusManager for the Logback/Spring paths, Log4j2's StatusLogger, or System.err for the
JUL/Quarkus paths) — see troubleshooting.md.
See also¶
- configuration.md — where
url,topic,token,username, andpasswordlive in each framework. - troubleshooting.md — the exact wording of the token-wins warning and every other diagnostic the engine can produce.