[GH-ISSUE #143] Sender authorization for public use #119

Closed
opened 2026-05-07 00:20:11 +02:00 by BreizhHardware · 10 comments

Originally created by @FedericoCeratto on GitHub (Feb 12, 2022).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/143

Hello and thanks for developing ntfy. Currently the topic works as a shared secret.
If a developer publishes an application that contains an hardcoded topic anybody can extract it and use it to send notifications.
(Applications might implement signature verification but receiving a large number of spam messages would consume battery and create a DoS vulnerability).

Additionally, the application should not create a hard dependency on a single public instance of Ntfy like ntfy.sh
The application should be able to switch to a different public server to receive notification from trusted senders. The sender could simply send a notification to every Ntfy instance and should not have to monitor which instances are available, or handle user/pass pairs etc.

Would you consider adding some authorization? I could suggest stateless server-side signature verification where the topic contains a base64-encoded public key and the server rejects any message that does not have a matching "Signature: " header.

Originally created by @FedericoCeratto on GitHub (Feb 12, 2022). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/143 Hello and thanks for developing ntfy. Currently the topic works as a shared secret. If a developer publishes an application that contains an hardcoded topic anybody can extract it and use it to send notifications. (Applications might implement signature verification but receiving a large number of spam messages would consume battery and create a DoS vulnerability). Additionally, the application should not create a hard dependency on a single public instance of Ntfy like ntfy.sh The application should be able to switch to a different public server to receive notification from trusted senders. The sender could simply send a notification to every Ntfy instance and should not have to monitor which instances are available, or handle user/pass pairs etc. Would you consider adding some authorization? I could suggest stateless server-side signature verification where the topic contains a base64-encoded public key and the server rejects any message that does not have a matching "Signature: <foo>" header.
BreizhHardware 2026-05-07 00:20:11 +02:00
Author
Owner

@binwiederhier commented on GitHub (Feb 12, 2022):

I added auth in the last release for selfhosted servers: https://ntfy.sh/docs/config/#access-control

Or did you mean for the public instance?

<!-- gh-comment-id:1037301234 --> @binwiederhier commented on GitHub (Feb 12, 2022): I added auth in the last release for selfhosted servers: https://ntfy.sh/docs/config/#access-control Or did you mean for the public instance?
Author
Owner

@binwiederhier commented on GitHub (Feb 12, 2022):

You can see a video of the app and a discussion here: https://www.reddit.com/r/selfhosted/comments/snulj5/as_requested_a_lot_by_you_guys_i_added_auth/

<!-- gh-comment-id:1037302696 --> @binwiederhier commented on GitHub (Feb 12, 2022): You can see a video of the app and a discussion here: https://www.reddit.com/r/selfhosted/comments/snulj5/as_requested_a_lot_by_you_guys_i_added_auth/
Author
Owner

@binwiederhier commented on GitHub (Feb 12, 2022):

There are also some public topics you can use to test it: github.com/binwiederhier/ntfy@2188643387 (diff-4ff92ab21f) (the docs for this are not live yet)

<!-- gh-comment-id:1037305467 --> @binwiederhier commented on GitHub (Feb 12, 2022): There are also some public topics you can use to test it: https://github.com/binwiederhier/ntfy/commit/218864338707a3eb7c3390c7fb09089091076347#diff-4ff92ab21f32a2846ac37bb30732d3475ed5a5c1f6a0637813e469213233d8cbR1177 (the docs for this are not live yet)
Author
Owner

@FedericoCeratto commented on GitHub (Feb 12, 2022):

@binwiederhier thanks for the answer. My question is specifically about stateless auth with public instances, so that the sender does not need to manage user/pass pairs and to trust the servers.

<!-- gh-comment-id:1037314230 --> @FedericoCeratto commented on GitHub (Feb 12, 2022): @binwiederhier thanks for the answer. My question is specifically about stateless auth with public instances, so that the sender does not need to manage user/pass pairs and to trust the servers.
Author
Owner

@binwiederhier commented on GitHub (Feb 12, 2022):

Yeah in the beginning of designing auth i wanted to add topic reservations to lease topics for X hours, with auto extending, for this exact purpose.

It definitely wouldn't be stateless, because it would have to persist through restarts.

<!-- gh-comment-id:1037338195 --> @binwiederhier commented on GitHub (Feb 12, 2022): Yeah in the beginning of designing auth i wanted to add topic reservations to lease topics for X hours, with auto extending, for this exact purpose. It definitely wouldn't be stateless, because it would have to persist through restarts.
Author
Owner

@binwiederhier commented on GitHub (Feb 12, 2022):

Another thought i had was shadow topics, basically allow basic auth user with user shadow:somepass where every password was allowed, and every topic+password combination effectively makes a new topic. So everyone could use mytopic as a topic, but you'd have to use your own key to publish/subscribe to see it

<!-- gh-comment-id:1037343868 --> @binwiederhier commented on GitHub (Feb 12, 2022): Another thought i had was shadow topics, basically allow basic auth user with user `shadow:somepass` where every password was allowed, and every topic+password combination effectively makes a new topic. So everyone could use mytopic as a topic, but you'd have to use your own key to publish/subscribe to see it
Author
Owner

@binwiederhier commented on GitHub (Feb 16, 2022):

Alright here are two ideas:

Temporary reservation

On a first come first serve basis, you define the auth mode and key you like in the POST of the first message, and then only you can write to it with the key you give. e.g.

curl -d "message 123" -H "Reserve: read-only hunter2" ntfy.sh/jay

# Alternative syntax idea:
curl -d "message 123" -H "Key: hunter2" -H "Everyone: read-only" ntfy.sh/jay

# Yet another alternative syntax idea (creates a temporary user):
curl -d "message 123" -u "jay:hunter2" -H "Everyone: read-only" ntfy.sh/jay

And then for 12 hours or whatever, that topic would be reserved to you, with others being able to read, but only you with Key: hunter2 being able to write, or until you publish another message.

Shadow topics

That'd be when you just pass a "Key: abc" header and your topic ntfy.sh/jay is essentially ntfy.sh/jay:abc under the hood. So you have a short topic "jay", but others can use it too with a different key.

<!-- gh-comment-id:1041914964 --> @binwiederhier commented on GitHub (Feb 16, 2022): Alright here are two ideas: ### Temporary reservation On a first come first serve basis, you define the auth mode and key you like in the POST of the first message, and then only you can write to it with the key you give. e.g. ``` curl -d "message 123" -H "Reserve: read-only hunter2" ntfy.sh/jay # Alternative syntax idea: curl -d "message 123" -H "Key: hunter2" -H "Everyone: read-only" ntfy.sh/jay # Yet another alternative syntax idea (creates a temporary user): curl -d "message 123" -u "jay:hunter2" -H "Everyone: read-only" ntfy.sh/jay ``` And then for 12 hours or whatever, that topic would be reserved to you, with others being able to read, but only you with `Key: hunter2` being able to write, or until you publish another message. ### Shadow topics That'd be when you just pass a "Key: abc" header and your topic ntfy.sh/jay is essentially ntfy.sh/jay:abc under the hood. So you have a short topic "jay", but others can use it too with a different key.
Author
Owner

@FedericoCeratto commented on GitHub (Feb 27, 2022):

@binwiederhier I updated the initial description. Maybe I should create a dedicated issue around redundancy/failover.

<!-- gh-comment-id:1053565731 --> @FedericoCeratto commented on GitHub (Feb 27, 2022): @binwiederhier I updated the initial description. Maybe I should create a dedicated issue around redundancy/failover.
Author
Owner

@dcousens commented on GitHub (May 7, 2022):

Alternatively, following the "shadow topic" idea by @binwiederhier, you could support for example

  • to publish, https://ntfy.sh/sw/foobar
  • to subscribe, https://ntfy.sh/sr/c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2.

The hex string c3ab... represents the sha256 hash of foobar.
/sw represents the shadow write-only route.
/sr represents the shadow read-only route.

When a shadow topic notification is published to /sw/foobar, the notification is distributed to subscribers of /sr/${sha256(foobar)}.

If someone attempted to publish to /sw/c3ab..., it would distribute that notification to /sr/181cd581758421220b8c53d143563a027b476601f1a837ec85ee6f08c2a82cad (sha256(sha256(foobar))), effectively a completely different irrelevant topic.

I think this lends itself to the following properties:

  • If c3ab... is revealed, you only have read capability for that topic.
  • If foobar is revealed, you have write capability for that topic.

I think this maintains the same security considerations as before, easy to guess topics are still low security; with added read/write permissions enforced by the server.

It is additionally stateless.


Probably the nicest part about this, is you don't need any cryptographic primitives to publish or subscribe to notifications.
This keeps curl as an easy integration point, without requiring complicated code or libraries.

<!-- gh-comment-id:1120210878 --> @dcousens commented on GitHub (May 7, 2022): Alternatively, following the "shadow topic" idea by @binwiederhier, you could support for example - to publish, `https://ntfy.sh/sw/foobar` - to subscribe, `https://ntfy.sh/sr/c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2`. The hex string `c3ab...` represents the sha256 hash of `foobar`. `/sw` represents the shadow write-only route. `/sr` represents the shadow read-only route. When a shadow topic notification is published to `/sw/foobar`, the notification is distributed to subscribers of `/sr/${sha256(foobar)}`. If someone attempted to publish to `/sw/c3ab...`, it would distribute that notification to `/sr/181cd581758421220b8c53d143563a027b476601f1a837ec85ee6f08c2a82cad` (sha256(sha256(foobar))), effectively a completely different irrelevant topic. I think this lends itself to the following properties: - If `c3ab...` is revealed, you **only** have read capability for that topic. - If `foobar` is revealed, you have write capability for that topic. I think this maintains the same security considerations as before, easy to guess topics are still low security; with added read/write permissions enforced by the server. It is additionally stateless. --- Probably the nicest part about this, is you don't need any cryptographic primitives to publish or subscribe to notifications. This keeps `curl` as an easy integration point, without requiring complicated code or libraries.
Author
Owner

@binwiederhier commented on GitHub (May 23, 2023):

Given that we now have username/password + access tokens, I don't think I want to create another way of authenticating against the server. So I'm closing this.

<!-- gh-comment-id:1559870347 --> @binwiederhier commented on GitHub (May 23, 2023): Given that we now have username/password + access tokens, I don't think I want to create another way of authenticating against the server. So I'm closing this.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#119
No description provided.