[GH-ISSUE #19] Auth #18

Closed
opened 2026-05-07 00:18:34 +02:00 by BreizhHardware · 42 comments

Originally created by @dwmccheyne on GitHub (Nov 24, 2021).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/19

I would like to require authentication to pub/sub to topics at least on private servers.
I think Google Identity would be a good provider here since authenticating to it is a familiar part of the types of workflows I would like to incorporate this into.

Originally created by @dwmccheyne on GitHub (Nov 24, 2021). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/19 I would like to require authentication to pub/sub to topics at least on private servers. I think Google Identity would be a good provider here since authenticating to it is a familiar part of the types of workflows I would like to incorporate this into.
Author
Owner

@binwiederhier commented on GitHub (Nov 24, 2021):

I'm not against adding optional authentication, but using Google seems a little against the selfhosting spirit, no?

I'll think about this a little and do some research. I think there are a lot of difficulties implementing any auth. Maybe auth shouldn't be done by ntfy but rather by nginx or some other proxy...

<!-- gh-comment-id:978489589 --> @binwiederhier commented on GitHub (Nov 24, 2021): I'm not against adding optional authentication, but using Google seems a little against the selfhosting spirit, no? I'll think about this a little and do some research. I think there are a lot of difficulties implementing any auth. Maybe auth shouldn't be done by ntfy but rather by nginx or some other proxy...
Author
Owner

@aslmx commented on GitHub (Nov 25, 2021):

👍

Interim step could be to support basic auth. Haven't tried if that would work?
Curl should support it, but would the android app?

<!-- gh-comment-id:979493380 --> @aslmx commented on GitHub (Nov 25, 2021): :+1: Interim step could be to support basic auth. Haven't tried if that would work? Curl should support it, but would the android app?
Author
Owner

@binwiederhier commented on GitHub (Nov 26, 2021):

I think I'll look at something with basic auth to begin with. Especially since that's incredibly easy to do with curl too.

<!-- gh-comment-id:979604102 --> @binwiederhier commented on GitHub (Nov 26, 2021): I think I'll look at something with basic auth to begin with. Especially since that's incredibly easy to do with curl too.
Author
Owner

@aslmx commented on GitHub (Nov 26, 2021):

It would maybe be enough to just make sure the App supports Basic Auth - which your http library, if you use one, might already support.

Then it would be up to the maintainer of the selfhosted instance to put http basic auth in the config of the reverse proxy.
I guess most people will run ntfy behind nginx or Traefik, etc.

They all support basic auth.

So that would be the "cheapest" way of achieving some kind of protection - it would protect everything in one go.

<!-- gh-comment-id:979786449 --> @aslmx commented on GitHub (Nov 26, 2021): It would maybe be enough to just make sure the App supports Basic Auth - which your http library, if you use one, might already support. Then it would be up to the maintainer of the selfhosted instance to put http basic auth in the config of the reverse proxy. I guess most people will run ntfy behind nginx or Traefik, etc. They all support basic auth. So that would be the "cheapest" way of achieving some kind of protection - it would protect everything in one go.
Author
Owner

@shadow00 commented on GitHub (Dec 1, 2021):

What implementing authentication via api tokens? For example, the creator of a topic can optionally include a token, and then whoever tries to subscribe to that topic afterwards has to provide the same token (this is effectively a password-protected topic). The content of said token is completely arbitrary (though perhaps should be limited to, say 64-128 characters/bytes).

This could be done for example via the "Authorization" header, or by simply including a "token" field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default.

More complex but more flexible variant: topic creator includes an "admin" token and a list of allowed "client" tokens. Anyone providing a valid client token can publish subscribe to the topic, and the list of allowed tokens can me changed only by providing the admin token as authentication. The list of client tokens could even be split into two, separating the clients that can publish to the topic and clients that can subscribe (the same token can be on both lists, and the two capabilities are separate - that way, we have clients that are publish-only, subscribe-only, and both).

This way:

  • A publisher cannot send a message without providing the appropriate token.
  • A subscriber cannot subscribe to a topic without providing the appropriate token.
  • An admin can request a list of the current tokens, add a token to a specific list, remove a token from a specific list.
    • Something like https://ntfy.sh/mytopic/tokens, https://ntfy.sh/mytopic/addtoken, https://ntfy.sh/mytopic/rmtoken,

The server administrator can decide via the config if the auth tokens expire with the topic or if they are persistent (can be easily saved in a dedicated json/yaml file).

Example auth.json:

{
    "mytopic": {
        "admin": ["LhaC8heEBOu9YPVc", "XqyNlCyqUDq6g7oM"],
        "pub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "iqp5qgmKenWjd1I6"],
        "sub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "ahPaEtqoY0i8MWwN"]
    },
    "topic2": {
        "admin": [],
        "pub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"],
        "sub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"]
    }
}

Note how mytopic has two admin tokens, iqp5qgmKenWjd1I6 can only publish, ahPaEtqoY0i8MWwN can only subscribe, and the other three can do both.
As for topic2, there are no admin tokens - so only those two client tokens would be able to pub/sub, and nobody would be able to change that list except the server administrator.

<!-- gh-comment-id:984142511 --> @shadow00 commented on GitHub (Dec 1, 2021): What implementing authentication via api tokens? For example, the creator of a topic can optionally include a token, and then whoever tries to subscribe to that topic afterwards has to provide the same token (this is effectively a password-protected topic). The content of said token is completely arbitrary (though perhaps should be limited to, say 64-128 characters/bytes). This could be done for example via the `"Authorization"` header, or by simply including a `"token"` field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default. More complex but more flexible variant: topic creator includes an "admin" token and a list of allowed "client" tokens. Anyone providing a valid client token can publish subscribe to the topic, and the list of allowed tokens can me changed only by providing the admin token as authentication. The list of client tokens could even be split into two, separating the clients that can publish to the topic and clients that can subscribe (the same token can be on both lists, and the two capabilities are separate - that way, we have clients that are publish-only, subscribe-only, and both). This way: - A publisher cannot send a message without providing the appropriate token. - A subscriber cannot subscribe to a topic without providing the appropriate token. - An admin can request a list of the current tokens, add a token to a specific list, remove a token from a specific list. - Something like `https://ntfy.sh/mytopic/tokens`, `https://ntfy.sh/mytopic/addtoken`, `https://ntfy.sh/mytopic/rmtoken`, The server administrator can decide via the config if the auth tokens expire with the topic or if they are persistent (can be easily saved in a dedicated json/yaml file). Example `auth.json`: ```json { "mytopic": { "admin": ["LhaC8heEBOu9YPVc", "XqyNlCyqUDq6g7oM"], "pub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "iqp5qgmKenWjd1I6"], "sub": ["NSgG47rbMLdDxl0L", "rppJwLr8HaEs2WtF", "1RoqplTLvIKvIAMM", "ahPaEtqoY0i8MWwN"] }, "topic2": { "admin": [], "pub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"], "sub": ["IyWmTqwmZuLNFPxZ", "WTliVPeTp602x51L"] } } ``` Note how `mytopic` has two admin tokens, `iqp5qgmKenWjd1I6` can only publish, `ahPaEtqoY0i8MWwN` can only subscribe, and the other three can do both. As for `topic2`, there are no admin tokens - so only those two client tokens would be able to pub/sub, and nobody would be able to change that list except the server administrator.
Author
Owner

@binwiederhier commented on GitHub (Dec 2, 2021):

Thank you very much for the incredibly detailed suggestion. That's awesome!

the creator of a topic can optionally include a token, and then whoever tries to subscribe to that topic afterwards has to provide the same token (this is effectively a password-protected topic).

So technically a topic is never created actively:

  • If caching is enabled, it just exists when there are cached messages until they expire (12h)
  • If caching is turned off, a topic never really exists for longer than a split second. A message is forwarded to all of its subscribers and then the topic is destroyed immediately.

I think this is solvable though.

This could be done for example via the "Authorization" header, or by simply including a "token" field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default.

.. admin token ..

As you may have noticed from the rest of ntfy, I like simple things, so I am not a big fan of the admin + client token idea (for now at least). I can totally imagine this being useful eventually, but for now I think your first idea can be adapted to work with the ephemeral topics.

How about this:

Topic-specfic auth

When you publish or subscribe to a topic, you can additionally send a Authorization: token ... header as you suggested, e.g.

Authorization: token xDsdAkksdjdfFBalADA

my message

or

Authorization: token xDsdAkksdjdfFBalADA
  • If an Authorization header is present and the topic is not known, the topic is reserved for topic-auth-reservation: 24h (configurable), during which time the topic will not be reaped and only requests with a valid auth can publish/subscribe
  • The topic expiration time is automatically extended as long as you are actively connected. So effectively a topic never expires as long as you are connected. And when you are disconnected, you have topic-auth-reservation to reconnect before the topic expires.

Server-wide auth

Instead of doing a topic specific Authorization, you configure a server-auth: mysecrettoken or something which applies to all topics. This would be the simplest way to make a private server.

All configs:

auth-mode: (none|server-wide|per-topic)     # defaults to none
server-auth: <token>
topic-auth-reservation: 24h 

Thoughts?

<!-- gh-comment-id:984261031 --> @binwiederhier commented on GitHub (Dec 2, 2021): Thank you very much for the incredibly detailed suggestion. That's awesome! > the creator of a topic can optionally include a token, and then whoever tries to subscribe to that topic afterwards has to provide the same token (this is effectively a password-protected topic). So technically a topic is never created actively: - If caching is enabled, it just exists when there are cached messages until they expire (12h) - If caching is turned off, a topic never really exists for longer than a split second. A message is forwarded to all of its subscribers and then the topic is destroyed immediately. I think this is solvable though. > This could be done for example via the "Authorization" header, or by simply including a "token" field along with the message/subscription request. Note that the server would not include the token when relaying a message. For public topics this field could be omitted, or assumed/left empty by default. > .. admin token .. As you may have noticed from the rest of ntfy, I like simple things, so I am not a big fan of the admin + client token idea (for now at least). I can totally imagine this being useful eventually, but for now I think your first idea can be adapted to work with the ephemeral topics. How about this: ## Topic-specfic auth When you publish or subscribe to a topic, you can additionally send a `Authorization: token ...` header as you suggested, e.g. ``` POST /mytopic HTTP/1.1 Authorization: token xDsdAkksdjdfFBalADA my message ``` or ``` GET /mytopic/json HTTP/1.1 Authorization: token xDsdAkksdjdfFBalADA ``` - If an `Authorization` header is present and the topic is not known, the topic is reserved for `topic-auth-reservation: 24h` (configurable), during which time the topic will not be reaped and only requests with a valid auth can publish/subscribe - The topic expiration time is automatically extended as long as you are actively connected. So effectively a topic never expires as long as you are connected. And when you are disconnected, you have `topic-auth-reservation` to reconnect before the topic expires. ## Server-wide auth Instead of doing a topic specific `Authorization`, you configure a `server-auth: mysecrettoken` or something which applies to all topics. This would be the simplest way to make a private server. ## All configs: ``` auth-mode: (none|server-wide|per-topic) # defaults to none server-auth: <token> topic-auth-reservation: 24h ``` Thoughts?
Author
Owner

@shadow00 commented on GitHub (Dec 2, 2021):

Lol, I guess I got a little carried away. I like your idea very much - both the topic-specific auth, as well as the server-wide auth (and it doesn't preclude the implementation of some kind of authorization logic on top of it in the future ;) )

How would you handle the case of topic-auth-reservation < cache-duration? I see the following options:

  • configuration error that prevents the server from starting (easiest to implement, but perhaps a bit limiting?)
  • topic becomes public, any previous cached message is kept but only accessible if the correct auth token is provided (too messy imo)
  • topic becomes public, any previous cached message becomes publically available (bad idea/potential security risk, defeats the purpose of authorization)
  • topic becomes public, any previous cached messages are deleted - effectively, the topic is unregistered and the server knows nothing about it anymore (this seems the best option to me)

What about making the per-topic auth duration dynamically configurable? Eg. by providing an additional (possibly optional) Reservation-period header (or maybe something with a better name). If the header is provided, use that when setting the grace period and renewing the topic; otherwise, the server-configured value is used by default. Server-side, this second parameter would be stored along with the auth token inside your reservation list.

<!-- gh-comment-id:984880171 --> @shadow00 commented on GitHub (Dec 2, 2021): Lol, I guess I got a little carried away. I like your idea very much - both the topic-specific auth, as well as the server-wide auth (and it doesn't preclude the implementation of some kind of authorization logic on top of it in the future ;) ) How would you handle the case of `topic-auth-reservation < cache-duration`? I see the following options: - configuration error that prevents the server from starting (easiest to implement, but perhaps a bit limiting?) - topic becomes public, any previous cached message is kept but only accessible if the correct auth token is provided (too messy imo) - topic becomes public, any previous cached message becomes publically available (bad idea/potential security risk, defeats the purpose of authorization) - topic becomes public, any previous cached messages are deleted - effectively, the topic is unregistered and the server knows nothing about it anymore (this seems the best option to me) What about making the per-topic auth duration dynamically configurable? Eg. by providing an additional (possibly optional) `Reservation-period` header (or maybe something with a better name). If the header is provided, use that when setting the grace period and renewing the topic; otherwise, the server-configured value is used by default. Server-side, this second parameter would be stored along with the auth token inside your reservation list.
Author
Owner

@aslmx commented on GitHub (Dec 2, 2021):

Haven't fully understood the last comments about tokens.
But please consider: adding API Tokens that I have to setup first for a topic will void the key selling point of ntfy for me and basically I could stick to use gotify.

<!-- gh-comment-id:984971072 --> @aslmx commented on GitHub (Dec 2, 2021): Haven't fully understood the last comments about tokens. But please consider: adding API Tokens that I have to setup first for a topic will void the key selling point of ntfy for me and basically I could stick to use gotify.
Author
Owner

@shadow00 commented on GitHub (Dec 2, 2021):

@aslmx it would be an optional feature. If you want, you can create a topic that requires a custom api key to publish/subscribe. If you don't want, you can keep using ntfy the same way you can do now, without any api key.

<!-- gh-comment-id:984988434 --> @shadow00 commented on GitHub (Dec 2, 2021): @aslmx it would be an optional feature. If you want, you can create a topic that requires a custom api key to publish/subscribe. If you don't want, you can keep using ntfy the same way you can do now, without any api key.
Author
Owner

@rigrig commented on GitHub (Dec 3, 2021):

Maybe there could also be a auth-mode: publish: everybody can subscribe (if you know the topic), but you need the server-auth token to publish?

And I guess it would be nice if server-auth could be a list, so you can hand out different tokens to different publishers.

<!-- gh-comment-id:985774881 --> @rigrig commented on GitHub (Dec 3, 2021): Maybe there could also be a `auth-mode: publish`: everybody can subscribe (if you know the topic), but you need the `server-auth` token to publish? And I guess it would be nice if `server-auth` could be a list, so you can hand out different tokens to different publishers.
Author
Owner

@binwiederhier commented on GitHub (Dec 3, 2021):

@aslmx Yeah don't worry, I'll leave the "no auth" a default. Every auth option I'll add will be opt-in, just like @shadow00 said

@rigrig If you read this comment from @shadow00, he had very similar ideas. I desperately want to keep things as simple as possible, and I also don't want to re-invent the wheel. I think I may need to read up on how others do auth, and how to do this properly. I don't really want to necessarily roll my own here.

That said, I think I can iterate on this. I can implement the server-wide one pretty easily and push that out, but I think I'll need a little bit of time for the others to get it right. Please keep suggestions coming!!

<!-- gh-comment-id:985780146 --> @binwiederhier commented on GitHub (Dec 3, 2021): @aslmx Yeah don't worry, I'll leave the "no auth" a default. Every auth option I'll add will be opt-in, just like @shadow00 said @rigrig If you read [this comment](https://github.com/binwiederhier/ntfy/issues/19#issuecomment-984142511) from @shadow00, he had very similar ideas. I desperately want to keep things as simple as possible, and I also don't want to re-invent the wheel. I think I may need to read up on how others do auth, and how to do this properly. I don't really want to necessarily roll my own here. That said, I think I can iterate on this. I can implement the `server-wide` one pretty easily and push that out, but I think I'll need a little bit of time for the others to get it right. Please keep suggestions coming!!
Author
Owner

@rigrig commented on GitHub (Dec 3, 2021):

I understand wanting to keep it simple, I just figured it would be nice to restrict what gets published to my server without clients needing to bother with tokens. (i.e. publish would be the same as server-wide, except you don't need a token to subscribe.)

<!-- gh-comment-id:985795422 --> @rigrig commented on GitHub (Dec 3, 2021): I understand wanting to keep it simple, I just figured it would be nice to restrict what gets published to my server without clients needing to bother with tokens. (i.e. `publish` would be the same as `server-wide`, except you don't need a token to subscribe.)
Author
Owner

@binwiederhier commented on GitHub (Dec 30, 2021):

Thank you for your comment. Fascinating! NATS sounds great. Didn't know it existed. It looks like a classic pubsub implementation. I'll look at it further, but I think it's probably a little too much for this little project, don't you think?

I would have to replace the guts of ntfy with NATS and for what? I am a strong believer in KISS, and this seems like the opposite of KISS. I'll mull it over a little though.

Also: This ticket is about Auth, so maybe we should move this convo somewhere else. Feel free to open a NATS ticket :-D

<!-- gh-comment-id:1002820641 --> @binwiederhier commented on GitHub (Dec 30, 2021): Thank you for your comment. Fascinating! NATS sounds great. Didn't know it existed. It looks like a classic pubsub implementation. I'll look at it further, but I think it's probably a little too much for this little project, don't you think? I would have to replace the guts of ntfy with NATS and for what? I am a strong believer in KISS, and this seems like the opposite of KISS. I'll mull it over a little though. Also: This ticket is about Auth, so maybe we should move this convo somewhere else. Feel free to open a NATS ticket :-D
Author
Owner

@binwiederhier commented on GitHub (Dec 30, 2021):

Just an update on the general status of this ticket: After the unified push ticket (#9), I'll work on this.

<!-- gh-comment-id:1002820813 --> @binwiederhier commented on GitHub (Dec 30, 2021): Just an update on the general status of this ticket: After the unified push ticket (#9), I'll work on this.
Author
Owner

@gc-ss commented on GitHub (Dec 31, 2021):

On the topic of NATS (yes! Definitely use it!) I have had great experience with an OSS layer on top of NATS: LiftBridge/NATS

https://github.com/liftbridge-io/liftbridge

Tyler and his team is fantastic and has OSS the very product he is building his company on.

Just drop by on their Slack to ask any questions you have - no matter how basic.

LiftBridge is a great product that makes use of NATS.

<!-- gh-comment-id:1003461097 --> @gc-ss commented on GitHub (Dec 31, 2021): On the topic of NATS (yes! Definitely use it!) I have had great experience with an OSS layer on top of NATS: LiftBridge/NATS https://github.com/liftbridge-io/liftbridge Tyler and his team is fantastic and has OSS the very product he is building his company on. Just drop by on their Slack to ask any questions you have - no matter how basic. LiftBridge is a great product that makes use of NATS.
Author
Owner

@binwiederhier commented on GitHub (Jan 1, 2022):

I kindly ask to move NATS discussions here: #78 :-)

<!-- gh-comment-id:1003554602 --> @binwiederhier commented on GitHub (Jan 1, 2022): I kindly ask to move NATS discussions here: #78 :-)
Author
Owner

@nmoseman commented on GitHub (Jan 20, 2022):

The only thing I need would be to have basic auth support in the client. I'm going to be running it behind a proxy like nginx anyways to enforce https-only and I can use that to set auth.

I have made the mistake of running things 'open' on the internet before and they just up ripe for abuse. Somebody will figure out how to abuse it. I won't do that for anything that allows people to use a service to send data.

<!-- gh-comment-id:1017115159 --> @nmoseman commented on GitHub (Jan 20, 2022): The only thing I need would be to have basic auth support in the client. I'm going to be running it behind a proxy like nginx anyways to enforce https-only and I can use that to set auth. I have made the mistake of running things 'open' on the internet before and they just up ripe for abuse. Somebody will figure out how to abuse it. I won't do that for anything that allows people to use a service to send data.
Author
Owner

@binwiederhier commented on GitHub (Jan 20, 2022):

The only thing I need would be to have basic auth support in the client

I have read a lot about auth these last few days and the more I read, the less I want to do anything fancy. I will likely try to iterate on this, starting with basic auth with a static key for everything. The Android app has to support it obviously, so you can't just put configs in nginx.

Somebody will figure out how to abuse it.

I don't disagree. People on the Internet are evil and auth is definitely better than no auth if it's a service just for you. That said, I have jumped through endless hoops to limit everything to the extreme: Subscription rate limits, requests per second, attachment size limits, cache size limits, topic limits, ... (see https://ntfy.sh/docs/config/#rate-limiting). And then there's also fail2ban to lock out the abusers (https://ntfy.sh/docs/config/#banning-bad-actors-fail2ban).

The problem is typically though as a self-hoster, you want NO LIMITS, you want to upload a 500 MB file to your phone whenever you want, and that's obviously only possible with auth.

Long story short. I get it. I'll do auth, soon :-D

<!-- gh-comment-id:1017118613 --> @binwiederhier commented on GitHub (Jan 20, 2022): > The only thing I need would be to have basic auth support in the client I have read a lot about auth these last few days and the more I read, the less I want to do anything fancy. I will likely try to iterate on this, starting with basic auth with a static key for everything. The Android app has to support it obviously, so you can't just put configs in nginx. > Somebody will figure out how to abuse it. I don't disagree. People on the Internet are evil and auth is definitely better than no auth if it's a service just for you. That said, I have jumped through endless hoops to limit everything to the extreme: Subscription rate limits, requests per second, attachment size limits, cache size limits, topic limits, ... (see https://ntfy.sh/docs/config/#rate-limiting). And then there's also fail2ban to lock out the abusers (https://ntfy.sh/docs/config/#banning-bad-actors-fail2ban). The problem is typically though as a self-hoster, you want NO LIMITS, you want to upload a 500 MB file to your phone whenever you want, and that's obviously only possible with auth. Long story short. I get it. I'll do auth, soon :-D
Author
Owner

@binwiederhier commented on GitHub (Jan 22, 2022):

This WIP PR (https://github.com/binwiederhier/ntfy/pull/114) implements this approach:

sqlite> SELECT * FROM user;
user        pass                                                          role      
----------  ------------------------------------------------------------  ----------
phil        $2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu  admin     
ben         $2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL.  user      
marian      $2a$06$N/BcXR0g6XUlmWttMqciWugR6xQKm2lVj31HLid6Mc4cnzpeOMgnq  user      

sqlite> SELECT * FROM topic;
topic          anon_read   anon_write
-------------  ----------  ----------
announcements  1           0         

sqlite> SELECT * FROM topic_user;
topic       user        read        write     
----------  ----------  ----------  ----------
alerts      ben         1           1         
alerts      marian      1           0         

In this example, phil can do everything, ben can read and write only to alerts and marian can read from alerts. Anonymous users can read from announcements.

There will be the following config params:

auth-file: /var/lib/ntfy/user.db

# Defines the fallback if no entry in the database is found
auth-default-read: false
auth-default-write: false

ntfy.sh will be set to auth-default-read/write: true, since everyone can write/read from everything.

I like this design a lot. It's super simple, yet infinitely flexible.

Feedback required: What I am unsure about is

  1. whether or not to combine this SQLite database with the message cache.db. Currently there is /var/cache/ntfy/cache.db that contains messages. And now there will be /var/lib/ntfy/user.db. We could just combine them to /var/lib/ntfy/database.db.
  2. whether or not I need to write an admin CLI or web UI for this. I will eventually make a proper UI, obviously..
<!-- gh-comment-id:1019347915 --> @binwiederhier commented on GitHub (Jan 22, 2022): This WIP PR (https://github.com/binwiederhier/ntfy/pull/114) implements this approach: ``` sqlite> SELECT * FROM user; user pass role ---------- ------------------------------------------------------------ ---------- phil $2a$06$.4W0LI5mcxzxhpjUvpTaNeu0MhRO0T7B.CYnmAkRnlztIy7PrSODu admin ben $2a$06$skJK/AecWCUmiCjr69ke.Ow/hFA616RdvJJPxnI221zyohsRlyXL. user marian $2a$06$N/BcXR0g6XUlmWttMqciWugR6xQKm2lVj31HLid6Mc4cnzpeOMgnq user sqlite> SELECT * FROM topic; topic anon_read anon_write ------------- ---------- ---------- announcements 1 0 sqlite> SELECT * FROM topic_user; topic user read write ---------- ---------- ---------- ---------- alerts ben 1 1 alerts marian 1 0 ``` In this example, `phil` can do everything, `ben` can read and write only to `alerts` and `marian` can read from `alerts`. Anonymous users can read from `announcements`. There will be the following config params: ``` auth-file: /var/lib/ntfy/user.db # Defines the fallback if no entry in the database is found auth-default-read: false auth-default-write: false ``` ntfy.sh will be set to `auth-default-read/write: true`, since everyone can write/read from everything. I like this design a lot. It's super simple, yet infinitely flexible. **Feedback required:** What I am unsure about is 1. whether or not to combine this SQLite database with the message cache.db. Currently there is `/var/cache/ntfy/cache.db` that contains messages. And now there will be `/var/lib/ntfy/user.db`. We could just combine them to `/var/lib/ntfy/database.db`. 2. whether or not I need to write an admin CLI or web UI for this. I will eventually make a proper UI, obviously..
Author
Owner

@binwiederhier commented on GitHub (Jan 24, 2022):

i would combine them but allow a user to via the cmd to pick via a flag if the system runs as a single service or as a archetype of each service .

Thank you for your response. I think you must have misunderstood my comment. I was merely talking about one sqlite database vs. two, not about two services/binaries. For now I opted to a different database for user+access management.

Here's an excerpt from the user/access management as I have implemented it currently:

# Create admin user phil
$  ntfy user add --role admin phil 
Password:
Confirm:
User phil added with role admin

# Create normal user ben
$ ntfy user add ben
Password:
Confirm:
User ben added with role user

# Grant read-write access for ben to topic mytopic
$ ntfy access ben mytopic rw
Granted read-write access to topic mytopic

User ben (user)
- read-write access to topic mytopic

# Grant read-only access for ben to topic readme
$ ntfy access ben readme read-only
Granted read-only access to topic readme

User ben (user)
- read-write access to topic mytopic
- read-only access to topic readme

# Grant access to anonymous users to announcements topic
$ ntfy access everyone announcements read-only
Granted read-only access to topic announcements

User * (anonymous)
- read-only access to topic announcements
- read-write access to all (other) topics (server config)

# Show entire access control list
$ ntfy access
User phil (admin)
- read-write access to all topics (admin role)
User ben (user)
- read-write access to topic mytopic
- read-only access to topic readme
User * (anonymous)
- read-only access to topic announcements
- read-write access to all (other) topics (server config)

# Not allowed because anonymous user does not have any permissions to any topics
$ curl -d hi localhost/mytopic
{"code":40301,"http":403,"error":"forbidden"}

# Allowed because phil is admin
$ curl -d hi -u phil:phil localhost/readme
{"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"}

$ curl -d "important announcement" -u phil:phil localhost/announcements
{"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"}

# Allowed because ben has read-write permission to topic mytopic
$ curl -d hi -u ben:ben localhost/mytopic
{"id":"sxz1Wky3zW","time":1643038381,"event":"message","topic":"mytopic","message":"hi"}

# Not allowed because ben only has read permissions to topic readme
$ curl -d hi -u ben:ben localhost/readme 
{"code":40301,"http":403,"error":"forbidden

# Allowed because ben has read permissions to topic readme
$ curl -u ben:ben "localhost/readme/json?poll=1"
{"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"}

# Allowed because the "everyone" user has read access to announcements
$ curl "localhost/announcements/json?poll=1"
{"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"}
<!-- gh-comment-id:1020233029 --> @binwiederhier commented on GitHub (Jan 24, 2022): > i would combine them but allow a user to via the cmd to pick via a flag if the system runs as a single service or as a archetype of each service . Thank you for your response. I think you must have misunderstood my comment. I was merely talking about one sqlite database vs. two, not about two services/binaries. For now I opted to a different database for user+access management. Here's an excerpt from the user/access management as I have implemented it currently: ``` bash # Create admin user phil $ ntfy user add --role admin phil Password: Confirm: User phil added with role admin # Create normal user ben $ ntfy user add ben Password: Confirm: User ben added with role user # Grant read-write access for ben to topic mytopic $ ntfy access ben mytopic rw Granted read-write access to topic mytopic User ben (user) - read-write access to topic mytopic # Grant read-only access for ben to topic readme $ ntfy access ben readme read-only Granted read-only access to topic readme User ben (user) - read-write access to topic mytopic - read-only access to topic readme # Grant access to anonymous users to announcements topic $ ntfy access everyone announcements read-only Granted read-only access to topic announcements User * (anonymous) - read-only access to topic announcements - read-write access to all (other) topics (server config) # Show entire access control list $ ntfy access User phil (admin) - read-write access to all topics (admin role) User ben (user) - read-write access to topic mytopic - read-only access to topic readme User * (anonymous) - read-only access to topic announcements - read-write access to all (other) topics (server config) # Not allowed because anonymous user does not have any permissions to any topics $ curl -d hi localhost/mytopic {"code":40301,"http":403,"error":"forbidden"} # Allowed because phil is admin $ curl -d hi -u phil:phil localhost/readme {"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"} $ curl -d "important announcement" -u phil:phil localhost/announcements {"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"} # Allowed because ben has read-write permission to topic mytopic $ curl -d hi -u ben:ben localhost/mytopic {"id":"sxz1Wky3zW","time":1643038381,"event":"message","topic":"mytopic","message":"hi"} # Not allowed because ben only has read permissions to topic readme $ curl -d hi -u ben:ben localhost/readme {"code":40301,"http":403,"error":"forbidden # Allowed because ben has read permissions to topic readme $ curl -u ben:ben "localhost/readme/json?poll=1" {"id":"zdf7mRUXWD","time":1643038509,"event":"message","topic":"readme","message":"hi"} # Allowed because the "everyone" user has read access to announcements $ curl "localhost/announcements/json?poll=1" {"id":"5AgEgeBGTU","time":1643038727,"event":"message","topic":"announcements","message":"important announcement"} ```
Author
Owner

@gc-ss commented on GitHub (Jan 24, 2022):

@binwiederhier, a different and dedicated sqlite database per usecase makes a lot of sense and is really appreciated.

For example, I can now apply (https://litestream.io/) to the user+access management sqlite database and have a fairly reliable user+access serdes for ntfy on less reliable commodity servers.

Still not as reliable as LiftBridge/NATS but way simpler and practically close for very low user velocity!

<!-- gh-comment-id:1020239922 --> @gc-ss commented on GitHub (Jan 24, 2022): @binwiederhier, a different and dedicated sqlite database per usecase makes a lot of sense and is really appreciated. For example, I can now apply (https://litestream.io/) to the user+access management sqlite database and have a fairly reliable user+access serdes for ntfy on less reliable commodity servers. Still not as reliable as LiftBridge/NATS but way simpler and practically close for very low user velocity!
Author
Owner

@cmeis commented on GitHub (Jan 24, 2022):

Oops, haven't pulled over my comments from the discord, will do now:

+1 for separate databases (user auth / cache)

I would suggest making access rules with wildcards at least a possibility. For starters (to be honest: for most cases) I'd like to see an asterisk wildcard, i.e. an access rule for "datacenter1-*" matching all topics starting with "datacenter1-".

<!-- gh-comment-id:1020243096 --> @cmeis commented on GitHub (Jan 24, 2022): Oops, haven't pulled over my comments from the discord, will do now: +1 for separate databases (user auth / cache) I would suggest making access rules with wildcards at least a possibility. For starters (to be honest: for most cases) I'd like to see an asterisk wildcard, i.e. an access rule for "datacenter1-*" matching all topics starting with "datacenter1-".
Author
Owner

@binwiederhier commented on GitHub (Jan 26, 2022):

Still working on this. The server side is solid and working, and I've written tests for pretty much everything. I've also started wireframing the Android changes. It's gonna be a lot of work unfortunately.

220125 11-28-56 Selection 001

220125 12-00-09 Selection 001

<!-- gh-comment-id:1021841524 --> @binwiederhier commented on GitHub (Jan 26, 2022): Still working on this. The server side is solid and working, and I've written tests for pretty much everything. I've also started wireframing the Android changes. It's gonna be a lot of work unfortunately. ![220125 11-28-56 Selection 001](https://user-images.githubusercontent.com/664597/151102249-5b24dee0-5cef-4341-b21f-62a20d48e5ce.png) ![220125 12-00-09 Selection 001](https://user-images.githubusercontent.com/664597/151102255-edf77ffe-3e65-4c4e-aed8-39e64b35ee8b.png)
Author
Owner

@julianfoad commented on GitHub (Jan 27, 2022):

Even though you've gone down this road, I still want to record what I mentioned in the chat a few weeks ago, about how I'm disillusioned with trying to self-host services that take the Do-It-Yourself Auth approach with their own user-password database, their own rules for valid usernames, their own system of roles and permissions, their own security model, and expect me to directly expose their own security implementation to the internet while running on my home server. Mainly my concern is not about security against hackers but about my ability to manage consistent logins, usernames, password updates (and preferably single-sign-on too) across several small self-hosted services.

The best way to support self-hosting (and I mean to say this to all self-hostable projects) is to provide the simple ability to connect to standard auth mechanisms.

I wish you could even now reconsider instead to make the client compatible with external (reverse-proxy based) auth standards such as http-basic (the simplest) and (the next step up) the session-cookie based "forward auth" flow which is described well in Authelia's architecture doc page. Authelia is just one such auth front-end, not a special case.

With those kinds of auth schemes, adding awareness of "users" to the server is completely optional. You can start with a system where just "successful authentication" according to the external auth front-end is enough and once past that then whoever authenticated will have full access to the server (the old existing ntfy server before you started adding auth awareness). Then if you want to add "user accounts" to the server you don't need to add authentication code but merely look at the "Remote-User" HTTP header on every request, which is added for you by the reverse proxy in combination with the auth front-end -- explained in Authelia - How can the backend be aware of the authenticated users?

<!-- gh-comment-id:1023118885 --> @julianfoad commented on GitHub (Jan 27, 2022): Even though you've gone down this road, I still want to record what I mentioned in the chat a few weeks ago, about how I'm disillusioned with trying to self-host services that take the Do-It-Yourself Auth approach with their own user-password database, their own rules for valid usernames, their own system of roles and permissions, their own security model, and expect me to directly expose their own security implementation to the internet while running on my home server. Mainly my concern is not about security against hackers but about my ability to manage consistent logins, usernames, password updates (and preferably single-sign-on too) across several small self-hosted services. The best way to support self-hosting (and I mean to say this to all self-hostable projects) is to provide the simple ability to connect to standard auth mechanisms. I wish you could even now reconsider instead to make the client compatible with external (reverse-proxy based) auth standards such as http-basic (the simplest) and (the next step up) the session-cookie based "forward auth" flow which is described well in [Authelia's architecture doc page](https://www.authelia.com/docs/home/architecture.html). Authelia is just one such auth front-end, not a special case. With those kinds of auth schemes, adding awareness of "users" to the server is completely optional. You can start with a system where just "successful authentication" according to the external auth front-end is enough and once past that then whoever authenticated will have full access to the server (the old existing ntfy server before you started adding auth awareness). Then if you want to add "user accounts" to the server you don't need to add authentication code but merely look at the "Remote-User" HTTP header on every request, which is added for you by the reverse proxy in combination with the auth front-end -- explained in [Authelia - How can the backend be aware of the authenticated users?](https://www.authelia.com/docs/deployment/supported-proxies/#how-can-the-backend-be-aware-of-the-authenticated-users)
Author
Owner

@julianfoad commented on GitHub (Jan 27, 2022):

Actually the "forward auth" flow is documented perhaps more generically in Traefik docs.

Example, snippets from my Authelia configuration.yml:

access_control:
  rules:
    # Unauthenticated public resources
    - domain: ['blog.example.org']
      policy: bypass
    # Authentication required for my ntfy service (any user I've configured)
    - domain: ['ntfy.example.org']
      policy: one_factor
    # Stronger auth, restricted to admins, for admin services
    - domain: ['admin.example.org']
      subject: "group:admins"
      policy: two_factor

and users_database.yml:

users:
  me: { groups: ['admins'], password: '$argon2id$v=19$m=1048576,t=1,p=8$xxxxxxxx' }
  other_user: { groups: ['users'], password: '...' }

and my Traefik-2 middleware rule, which reference from the routing rule of each service that I want protected:

http:
  middlewares:
    middlewares-authelia:
      forwardAuth:
        address: "http://authelia:9091/api/verify?rd=https://{{ authelia_login_domain }}"
        trustForwardHeader: true
        authResponseHeaders:
          - "Remote-User"
          - "Remote-Groups"
<!-- gh-comment-id:1023130587 --> @julianfoad commented on GitHub (Jan 27, 2022): Actually the "forward auth" flow is documented perhaps more generically in [Traefik docs](https://doc.traefik.io/traefik/middlewares/http/forwardauth/). Example, snippets from my Authelia [configuration.yml](https://www.authelia.com/docs/configuration/access-control.html): ``` access_control: rules: # Unauthenticated public resources - domain: ['blog.example.org'] policy: bypass # Authentication required for my ntfy service (any user I've configured) - domain: ['ntfy.example.org'] policy: one_factor # Stronger auth, restricted to admins, for admin services - domain: ['admin.example.org'] subject: "group:admins" policy: two_factor ``` and [users_database.yml](https://www.authelia.com/docs/configuration/authentication/file.html): ``` users: me: { groups: ['admins'], password: '$argon2id$v=19$m=1048576,t=1,p=8$xxxxxxxx' } other_user: { groups: ['users'], password: '...' } ``` and my Traefik-2 middleware rule, which reference from the routing rule of each service that I want protected: ``` http: middlewares: middlewares-authelia: forwardAuth: address: "http://authelia:9091/api/verify?rd=https://{{ authelia_login_domain }}" trustForwardHeader: true authResponseHeaders: - "Remote-User" - "Remote-Groups" ```
Author
Owner

@binwiederhier commented on GitHub (Jan 27, 2022):

I appreciate all the input. I will review all of this later. I did do a whole lot of research and asked coworkers about what to do here. My conclusion was that there is no standard way of doing this, at least not for the use case o want.

That said, the implementation I made is very easy to replace or even augment. For example, the authentication can likely be delegated entirely to another system (i e. username and password), while the authorization is kept in ntfy. I am more than happy to integrate other systems, i just didn't know which since they all didn't seem to fit.

Like, for instance: oauth2 had a web based flow. If I want to support curl with user/pass, then do I return "unauthorized" with a web link in curl..?! You get the problem.

I'd really appreciate detailed help on how to integrate one of these solutions. I am happy to accommodate them, as long as they can stand next to the no-dependency-integrated one.

<!-- gh-comment-id:1023139440 --> @binwiederhier commented on GitHub (Jan 27, 2022): I appreciate all the input. I will review all of this later. I did do a whole lot of research and asked coworkers about what to do here. My conclusion was that there is no standard way of doing this, at least not for the use case o want. That said, the implementation I made is very easy to replace or even augment. For example, the authentication can likely be delegated entirely to another system (i e. username and password), while the authorization is kept in ntfy. I am more than happy to integrate other systems, i just didn't know which since they all didn't seem to fit. Like, for instance: oauth2 had a web based flow. If I want to support curl with user/pass, then do I return "unauthorized" with a web link in curl..?! You get the problem. I'd really appreciate detailed help on how to integrate one of these solutions. I am happy to accommodate them, as long as they can stand next to the no-dependency-integrated one.
Author
Owner

@binwiederhier commented on GitHub (Jan 27, 2022):

I gotta say Authelia and Traefik look very interesting, though this is what I found with most of these solutions:

Authelia is an open source authentication and authorization server protecting modern web applications

Neither the curl use case nor the Android app are "web applications". If there is an easy way to accommodate these two, then I'd be game. I'll look some more. @julianfoad I'm also more than happy to discuss on Discord/Matrix.

As for Zitadel, @gedw99, it says

ZITADEL only needs Kubernetes for orchestration and CockroachDB as storage.

The "only" here for me is almost ironic. :-)

<!-- gh-comment-id:1023153171 --> @binwiederhier commented on GitHub (Jan 27, 2022): I gotta say Authelia and Traefik look very interesting, though this is what I found with most of these solutions: > Authelia is an open source authentication and authorization server protecting modern *web applications* Neither the curl use case nor the Android app are "web applications". If there is an easy way to accommodate these two, then I'd be game. I'll look some more. @julianfoad I'm also more than happy to discuss on Discord/Matrix. As for Zitadel, @gedw99, it says > ZITADEL only needs Kubernetes for orchestration and CockroachDB as storage. The "only" here for me is almost ironic. :-)
Author
Owner

@gc-ss commented on GitHub (Jan 27, 2022):

Concur that Zitadelle is a fantastic piece of software. There used to be issues of running it just with docker but I worked with their team to tease those issues out - docker-compose should work right OOB now (If not, please let me know).

They also have a generous free tier.

as long as they can stand next to the no-dependency-integrated one.

That said, for something lightweight like ntfy authentik is extremely simple and more interestingly - wouldn't require ntfy to be auth aware at all (depends on what level of authz we want ntfy to support) - which checks the no-dependency-integrated box

If Authelia looks like a good fit, but you need "non webapp" support - authentik should be a great solution. They don't have any getting started guides (I will be trying to fix that soon in a few months) - so just run the docker-compose and check it out right away or jump in on the chat with any questions.

https://goauthentik.io/

<!-- gh-comment-id:1023391833 --> @gc-ss commented on GitHub (Jan 27, 2022): Concur that Zitadelle is a fantastic piece of software. There used to be issues of running it just with docker but I worked with their team to tease those issues out - `docker-compose` should work right OOB now (If not, please let me know). They also have a generous free tier. > as long as they can stand next to the no-dependency-integrated one. That said, for something lightweight like `ntfy` authentik is extremely simple and more interestingly - wouldn't require `ntfy` to be auth aware at all (depends on what level of authz we want `ntfy` to support) - which checks the no-dependency-integrated box If Authelia looks like a good fit, but you need "non webapp" support - authentik should be a great solution. They don't have any getting started guides (I will be trying to fix that soon in a few months) - so just run the `docker-compose` and check it out right away or jump in on the chat with any questions. https://goauthentik.io/
Author
Owner

@binwiederhier commented on GitHub (Jan 28, 2022):

Progress

220128 16-09-09 Selection 001

220128 16-08-45 Selection 001

220128 16-09-00 Selection 001

220128 16-10-16 Selection 001

220128 16-10-04 Selection 001

<!-- gh-comment-id:1024638140 --> @binwiederhier commented on GitHub (Jan 28, 2022): Progress ![220128 16-09-09 Selection 001](https://user-images.githubusercontent.com/664597/151621767-66e4541b-2d46-4166-bc0f-45ed79148357.png) ![220128 16-08-45 Selection 001](https://user-images.githubusercontent.com/664597/151621773-55fff8ac-22f4-44f5-9fb7-04fe84e809ba.png) ![220128 16-09-00 Selection 001](https://user-images.githubusercontent.com/664597/151621769-6b1604df-6e57-4f20-80de-51020d0c645a.png) ![220128 16-10-16 Selection 001](https://user-images.githubusercontent.com/664597/151621880-cce091f9-e15f-406e-a84a-f6564764a259.png) ![220128 16-10-04 Selection 001](https://user-images.githubusercontent.com/664597/151621888-f7c2f923-3305-4429-b85f-e7984082fc87.png)
Author
Owner

@binwiederhier commented on GitHub (Jan 30, 2022):

Progress:
220129 22-30-48 Selection 001

220129 22-31-01 Selection 001

220129 22-31-14 Selection 001

<!-- gh-comment-id:1025060389 --> @binwiederhier commented on GitHub (Jan 30, 2022): Progress: ![220129 22-30-48 Selection 001](https://user-images.githubusercontent.com/664597/151685606-a57f68a3-1415-434f-857b-816fd744c156.png) ![220129 22-31-01 Selection 001](https://user-images.githubusercontent.com/664597/151685608-c57f4b2b-cfc1-408a-98f3-b2456f6a55d5.png) ![220129 22-31-14 Selection 001](https://user-images.githubusercontent.com/664597/151685610-b2c071b8-7969-4c59-a387-5cbf5716eee1.png)
Author
Owner

@binwiederhier commented on GitHub (Jan 31, 2022):

Alright folks this is "it".

I am soliciting feedback now that it's feature complete. I find it a little awkward and complicated. It's definitely not the "just works" kinda thing you'd expect.

Notes:
a) The "subscription settings" are a little weird, because they only contain the login stuff right now. There will be topic-specific settings (notification sound, paused notifications, min priority, ...) too later.
b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?
c) I think I definitely have to indicate in the main view when the auth fails. Right now it just says "reconnecting ..." forever.

Here's a full video of the entire flow:
https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ

<!-- gh-comment-id:1025295638 --> @binwiederhier commented on GitHub (Jan 31, 2022): Alright folks this is "it". **I am soliciting feedback now that it's feature complete.** I find it a little awkward and complicated. It's definitely not the "just works" kinda thing you'd expect. Notes: a) The "subscription settings" are a little weird, because they only contain the login stuff right now. There will be topic-specific settings (notification sound, paused notifications, min priority, ...) too later. b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think? c) I think I definitely have to indicate in the main view when the auth fails. Right now it just says "reconnecting ..." forever. Here's a full video of the entire flow: https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ
Author
Owner

@gc-ss commented on GitHub (Jan 31, 2022):

b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?

I prefer things that are accessible to majority of people - so number over color (colorblindness)

<!-- gh-comment-id:1025297078 --> @gc-ss commented on GitHub (Jan 31, 2022): > b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think? I prefer things that are accessible to majority of people - so number over color (colorblindness)
Author
Owner

@Mek101 commented on GitHub (Jan 31, 2022):

Progress: 220129 22-30-48 Selection 001

I would remove "You can also add a user when adding a topic"

<!-- gh-comment-id:1025581026 --> @Mek101 commented on GitHub (Jan 31, 2022): > Progress: ![220129 22-30-48 Selection 001](https://user-images.githubusercontent.com/664597/151685606-a57f68a3-1415-434f-857b-816fd744c156.png) I would remove "You can also add a user when adding a topic"
Author
Owner

@Mek101 commented on GitHub (Jan 31, 2022):

b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think?

I prefer things that are accessible to majority of people - so number over color (colorblindness)

What does the Material Design guidelines say about that?

<!-- gh-comment-id:1025581370 --> @Mek101 commented on GitHub (Jan 31, 2022): > > b) I was thinking about visual indicators for which user a topic is using, e.g. little person indicators with a number or color. What do you think? > > I prefer things that are accessible to majority of people - so number over color (colorblindness) What does the Material Design guidelines say about that?
Author
Owner

@karmanyaahm commented on GitHub (Jan 31, 2022):

Here's a full video of the entire flow:
https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ

When anonymous has no access to any topics, does that include write access?

If so, shouldn't all topics that are UnifiedPush have write access for anonymous (so app servers can POST messages)? Maybe giving topics /up.* anonymous write by default could solve that.

<!-- gh-comment-id:1025739482 --> @karmanyaahm commented on GitHub (Jan 31, 2022): > Here's a full video of the entire flow: https://phil.nopaste.net/7xfchbUB31?a=0zi01nlZsJ When anonymous has no access to any topics, does that include write access? If so, shouldn't all topics that are UnifiedPush have write access for anonymous (so app servers can POST messages)? Maybe giving topics /up.* anonymous write by default could solve that.
Author
Owner

@binwiederhier commented on GitHub (Jan 31, 2022):

I prefer things that are accessible to majority of people - so number over color (colorblindness)

I agree. I'll do that.

When anonymous has no access to any topics, does that include write access?

There's a setting auth-default-access = [deny-all|read-only|read-write] that defines the anonymous access behavior. I could obviously also make a write-only for anonymous access, I didn't think there was a use case. Now there is one :-)

If so, shouldn't all topics that are UnifiedPush have write access for anonymous (so app servers can POST messages)? Maybe giving topics /up.* anonymous write by default could solve that.

A UnifiedPush topic is just a topic, so if you make it /up*, then you effectively let people use the server as if it was fully open (with a small name restriction). Right now, pattern based ACL rules are not supported, though it has been asked for by @cmeis before, and since you're effectively the second person to ask, I may just implement that.

For UP, I'd say the best we can do if you want a "private server" is what you described:

  • Set auth-default-access = deny-all in server.yml
  • Run ntfy access everyone "up*" write-only
  • Run ntfy user add --role admin myuser and assign that in the Android app (not done yet).
<!-- gh-comment-id:1025844894 --> @binwiederhier commented on GitHub (Jan 31, 2022): > I prefer things that are accessible to majority of people - so number over color (colorblindness) I agree. I'll do that. > When anonymous has no access to any topics, does that include write access? There's a setting `auth-default-access = [deny-all|read-only|read-write]` that defines the anonymous access behavior. I could obviously also make a `write-only` for anonymous access, I didn't think there was a use case. Now there is one :-) > If so, shouldn't all topics that are UnifiedPush have write access for anonymous (so app servers can POST messages)? Maybe giving topics /up.* anonymous write by default could solve that. A UnifiedPush topic is just a topic, so if you make it `/up*`, then you effectively let people use the server as if it was fully open (with a small name restriction). Right now, pattern based ACL rules are not supported, though it has been asked for by @cmeis before, and since you're effectively the second person to ask, I may just implement that. For UP, I'd say the best we can do if you want a "private server" is what you described: - Set `auth-default-access = deny-all` in `server.yml` - Run `ntfy access everyone "up*" write-only` - Run `ntfy user add --role admin myuser` and assign that in the Android app (not done yet).
Author
Owner

@binwiederhier commented on GitHub (Jan 31, 2022):

The more I think about it, the more I think I should disallow multiple users per server (in the app), i.e. you can only have one user per server and that is used for all topics. What do you think about that? It feels quite unnatural to allow multiple users for the same servers from within one app.

<!-- gh-comment-id:1025926638 --> @binwiederhier commented on GitHub (Jan 31, 2022): The more I think about it, the more I think I **should disallow multiple users per server (in the app)**, i.e. you can only have one user per server and that is used for all topics. What do you think about that? It feels quite unnatural to allow multiple users for the same servers from within one app.
Author
Owner

@cmeis commented on GitHub (Jan 31, 2022):

The more I think about it, the more I think I should disallow multiple users per server (in the app), i.e. you can only have one user per server and that is used for all topics. What do you think about that? It feels quite unnatural to allow multiple users for the same servers from within one app.

Yeah, that would make sense. Thought about it a new times, and I don't come up with a situation where one might need different users to the same server (testing scenarios aside).

<!-- gh-comment-id:1025932332 --> @cmeis commented on GitHub (Jan 31, 2022): > The more I think about it, the more I think I **should disallow multiple users per server (in the app)**, i.e. you can only have one user per server and that is used for all topics. What do you think about that? It feels quite unnatural to allow multiple users for the same servers from within one app. Yeah, that would make sense. Thought about it a new times, and I don't come up with a situation where one might need different users to the same server (testing scenarios aside).
Author
Owner

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

Video:
https://phil.nopaste.net/YhbTac9AoL?a=YgMgHVdXRv

Alright I am much happier with this. Now the app only supports one user per host, meaning there is no more awkward dropdown and the "login required" screen is only shown once when the user does not exist.

I also removed the "Subscription settings" entirely (for now) and added the mechanism that PeterCxy suggested to avoid exposing messages for non-public Firebase topics via a "poll_request" message (not shown in the video).

I think this is what i'll stick with. Now "all I need to do" is polish it a little more and add lots of docs.


For those who want to test, here are binaries:
ntfy binary: https://phil.nopaste.net/ntfy-auth-1?a=BA0OLM8HiE
ntfy Android app: https://phil.nopaste.net/ntfy-auth-app-1.apk?a=AuUjHSlgpk

# in the server.yml
auth-file: /home/pheckel/Code/ntfy/playground/user.db
auth-default-access: deny-all
<!-- gh-comment-id:1027134378 --> @binwiederhier commented on GitHub (Feb 1, 2022): **Video:** https://phil.nopaste.net/YhbTac9AoL?a=YgMgHVdXRv Alright I am much happier with this. Now the app only supports one user per host, meaning there is no more awkward dropdown and the "login required" screen is only shown once when the user does not exist. I also removed the "Subscription settings" entirely (for now) and added the mechanism that PeterCxy suggested to avoid exposing messages for non-public Firebase topics via a "poll_request" message (not shown in the video). I think this is what i'll stick with. Now "all I need to do" is polish it a little more and add lots of docs. --- For those who want to test, here are binaries: **ntfy binary:** https://phil.nopaste.net/ntfy-auth-1?a=BA0OLM8HiE **ntfy Android app:** https://phil.nopaste.net/ntfy-auth-app-1.apk?a=AuUjHSlgpk ``` yaml # in the server.yml auth-file: /home/pheckel/Code/ntfy/playground/user.db auth-default-access: deny-all ```
Author
Owner

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

Server side auth code is released in https://github.com/binwiederhier/ntfy/releases/tag/v1.14.0

Note to future self, so I don't lose the links:

<!-- gh-comment-id:1030049934 --> @binwiederhier commented on GitHub (Feb 4, 2022): Server side auth code is released in https://github.com/binwiederhier/ntfy/releases/tag/v1.14.0 Note to future self, so I don't lose the links: - https://doc.traefik.io/traefik/middlewares/http/forwardauth/ - https://www.authelia.com/docs/configuration/access-control.html - https://goauthentik.io/
Author
Owner

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

The Android app will be released soon, so I'd consider this done for now. Thanks everyone for the fantastic discussion and the input. 👍 👍 👍

If you have any other desires regarding auth, please open another ticket. One that I would see would be "allow integrating X" to use as external auth backend, an I'll likely do it if it's reasonable.

<!-- gh-comment-id:1030634806 --> @binwiederhier commented on GitHub (Feb 5, 2022): The Android app will be released soon, so I'd consider this done for now. Thanks everyone for the fantastic discussion and the input. :+1: :+1: :+1: If you have any other desires regarding auth, please open another ticket. One that I would see would be "allow integrating X" to use as external auth backend, an I'll likely do it if it's reasonable.
Author
Owner

@Kranzes commented on GitHub (Mar 14, 2024):

Hey, is it possible to authenticate via my own OpenID Connect Identity Provider?

<!-- gh-comment-id:1997713791 --> @Kranzes commented on GitHub (Mar 14, 2024): Hey, is it possible to authenticate via my own OpenID Connect Identity Provider?
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#18
No description provided.