android icon indicating copy to clipboard operation
android copied to clipboard

2FA support

Open RaphMad opened this issue 3 years ago • 8 comments

In a ticket for gotify server it was stated that 2FA should be added via external services: https://github.com/gotify/server/issues/461

This works well for the WebUI (I'm personally using traefik + authelia for 2FA in front of gotify).

Unfortunately this is a problem for the Android client application, which is not able to follow the redirect workflow imposed by 2FA. This seems to be a general problem I've seen for many other selfhosted projects that provide a WebUI + client - when adding external 2FA, usually the client application breaks.

So it seems there are 3 "solutions" to this dilemma:

  • Try to make the client "redirect / 2FA aware" (is this even possible in a good way? since all 2FA stuff happens on the initial http requests and therefore "outside" the API level)
  • Re-think the decision not to have "native" 2FA built into the server (which I guess would be easier to follow/implement client-side)
  • "Just accept" / maybe somewhere document that 2FA + Client app is not supported

Any thoughts on this / am I missing something?

RaphMad avatar May 30 '22 17:05 RaphMad

This sounds about right. Like said in the linked issue, I think that adding support for external auth providers should be the simplest solution (in comparison to natively implementing this).

jmattheis avatar May 30 '22 19:05 jmattheis

Hi, I'm quite new to Gotify but I've used a lot of Authentik lately. Is there news on the subject ? I would love to be able to use Authentik to secure Gotify.

LeVraiRoiDHyrule avatar Jan 04 '23 20:01 LeVraiRoiDHyrule

In a ticket for gotify server it was stated that 2FA should be added via external services: gotify/server#461

This works well for the WebUI (I'm personally using traefik + authelia for 2FA in front of gotify).

Unfortunately this is a problem for the Android client application, which is not able to follow the redirect workflow imposed by 2FA. This seems to be a general problem I've seen for many other selfhosted projects that provide a WebUI + client - when adding external 2FA, usually the client application breaks.

So it seems there are 3 "solutions" to this dilemma:

  • Try to make the client "redirect / 2FA aware" (is this even possible in a good way? since all 2FA stuff happens on the initial http requests and therefore "outside" the API level)
  • Re-think the decision not to have "native" 2FA built into the server (which I guess would be easier to follow/implement client-side)
  • "Just accept" / maybe somewhere document that 2FA + Client app is not supported

Any thoughts on this / am I missing something?

RaphMad, i have a question. Did you managed to get Gotify working with authelia 2FA in front of it? I'm trying to get it to work, but i can't get any messages to my mobile phone. I use nginx proxy manager with Authelia, the code that i put in advance is:

location /authelia {
    internal;
    set $upstream_authelia http://192.168.1.55:9091/api/verify; #ADD YOUR IP AND PORT OF AUTHELIA
    proxy_pass_request_body off;
    proxy_pass $upstream_authelia;    
    proxy_set_header Content-Length "";
 
    # Timeout if the real server is dead
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    client_body_buffer_size 128k;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr; 
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_redirect  http://  $scheme://;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;
    proxy_buffers 4 32k;
 
    send_timeout 5m;
    proxy_read_timeout 240;
    proxy_send_timeout 240;
    proxy_connect_timeout 240;
}
 
    location / {
        set $upstream_gotify http://192.168.1.57:3001;  #CHANGE NAME AND IP AND PORT
        proxy_pass $upstream_gotify;  #change name of the service
 
		auth_request /authelia;
		auth_request_set $target_url $scheme://$http_host$request_uri;
		auth_request_set $user $upstream_http_remote_user;
		auth_request_set $groups $upstream_http_remote_groups;
		proxy_set_header Remote-User $user;
		proxy_set_header Remote-Groups $groups;
		error_page 401 =302 https://auth.YOURDOMAIN.COM/?rd=$target_url; #change YOURDOMAIN.COM to your domain
 
		client_body_buffer_size 128k;
 
		proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
 
		send_timeout 5m;
		proxy_read_timeout 360;
		proxy_send_timeout 360;
		proxy_connect_timeout 360;
 
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Forwarded-Host $http_host;
		proxy_set_header X-Forwarded-Uri $request_uri;
		proxy_set_header X-Forwarded-Ssl on;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
		proxy_redirect  http://  $scheme://;
		proxy_http_version 1.1;
		proxy_set_header Connection "";
		proxy_cache_bypass $cookie_session;
		proxy_no_cache $cookie_session;
		proxy_buffers 64 256k;
 
		set_real_ip_from 192.168.1.0/16;
		real_ip_header X-Forwarded-For;
		real_ip_recursive on;
 
    }

Can you help me out?

Sarnog avatar Feb 15 '23 20:02 Sarnog

No, as far as I understood the mobile app needs to be able to understand/support the initial HTTP redirect any 2FA solution implies (browsers are built for this and have no problems) - so no real chance to solve this with authelia config.

Basically still waiting for app support, and its unfortunately one of those topics that can easily be seen as "out of scope" on that side either, so I don't blame the devs if it takes long / they decide to not support this use-case.

RaphMad avatar Feb 15 '23 21:02 RaphMad

I just got it working!

In the authelia config:

access_control:

  default_policy: deny
  rules:
    ## bypass rule
    - domain:
        - "gotify.YOURDOMAIN.COM" 
      policy: bypass
      resources:
      - '^/api([/?].*)?$'
    - domain: "gotify.YOURDOMAIN.COM"
      policy: two_factor

And in NginX Proxy Manager under the advance tab:

location /authelia {
    internal;
    set $upstream_authelia http://192.168.1.55:9091/api/verify; #ADD YOUR IP AND PORT OF AUTHELIA
    proxy_pass_request_body off;
    proxy_pass $upstream_authelia;    
    proxy_set_header Content-Length "";
 
    # Timeout if the real server is dead
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    client_body_buffer_size 128k;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr; 
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_redirect  http://  $scheme://;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;
    proxy_buffers 4 32k;
 
    send_timeout 5m;
    proxy_read_timeout 240;
    proxy_send_timeout 240;
    proxy_connect_timeout 240;
}
 
    location / {
        set $upstream_gotify http://192.168.1.57:3001;  #CHANGE NAME AND IP AND PORT
        proxy_pass $upstream_gotify;  #change name of the service
 
		auth_request /authelia;
		auth_request_set $target_url $scheme://$http_host$request_uri;
		auth_request_set $user $upstream_http_remote_user;
		auth_request_set $groups $upstream_http_remote_groups;
		proxy_set_header Remote-User $user;
		proxy_set_header Remote-Groups $groups;
		error_page 401 =302 https://auth.YOURDOMAIN.COM/?rd=$target_url; #change YOURDOMAIN.COM to your domain
 
		client_body_buffer_size 128k;
 
		proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
 
		send_timeout 5m;
		proxy_read_timeout 360;
		proxy_send_timeout 360;
		proxy_connect_timeout 360;
 
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Forwarded-Host $http_host;
		proxy_set_header X-Forwarded-Uri $request_uri;
		proxy_set_header X-Forwarded-Ssl on;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
		proxy_redirect  http://  $scheme://;
		proxy_http_version 1.1;
		proxy_set_header Connection "";
		proxy_cache_bypass $cookie_session;
		proxy_no_cache $cookie_session;
		proxy_buffers 64 256k;
 
		set_real_ip_from 192.168.1.0/16;
		real_ip_header X-Forwarded-For;
		real_ip_recursive on;
 
    }

Rebooted authelia and when i want to login to the web GUI, i got 2FA from authelia, and when i sended a message to my android mobile phone, i received it. I'm not home, so i got it externally.

Was searching for this solution for months, so i thought i'll share it with you guys!

Sarnog avatar Feb 15 '23 21:02 Sarnog

Ah thats cool, I'll also try it!

RaphMad avatar Feb 15 '23 21:02 RaphMad

Hm I think it is still kind of an "out of band" solution - so you logged in on the web GUI (on your phone?) first, and then the app started working?

So it seems the app can handle the case where you are already logged in on the 2FA/Authelia level and you get forwarded to the actual gotify page without intervention. But did you also test the unauthenticated case where 2FA is required? (I'm asking because this would require the app to somehow render a frame that displays the web page containing the authelia login prompt, which seems very unlikely to already be implemented).

But I'm purely speculating here, haven't had the time to try anything by myself!

RaphMad avatar Feb 16 '23 09:02 RaphMad

I noticed that not all messages where working. I couldn't login to the android app neighter, i tried to figure it out and i think i got it completly working now.

I can login to the app as well and all the messages are comming through. If i open the webinterface from gotify in https://gotify.YOURDOMAIN.COM i get authelia 2FA first.

In the authelia config:

access_control:

  default_policy: deny
  rules:
    ## bypass rule
    - domain:
        - "gotify.YOURDOMAIN.COM" 
      policy: bypass
      resources:
      - '^/api([/?].*)?$'
      - '/message'
      - '/health'
      - '/static/'
      - '/favicon.ico'
      - '/'
    - domain: "gotify.YOURDOMAIN.COM"
      policy: two_factor

And in NginX Proxy Manager under the advance tab:

location /authelia {
    internal;
    set $upstream_authelia http://192.168.1.55:9091/api/verify; #ADD YOUR IP AND PORT OF AUTHELIA
    proxy_pass_request_body off;
    proxy_pass $upstream_authelia;    
    proxy_set_header Content-Length "";
 
    # Timeout if the real server is dead
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    client_body_buffer_size 128k;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr; 
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_redirect  http://  $scheme://;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;
    proxy_buffers 4 32k;
 
    send_timeout 5m;
    proxy_read_timeout 240;
    proxy_send_timeout 240;
    proxy_connect_timeout 240;
}
 
    location / {
        set $upstream_gotify http://192.168.1.57:3001;  #CHANGE NAME AND IP AND PORT
        proxy_pass $upstream_gotify;  #change name of the service
 
		auth_request /authelia;
		auth_request_set $target_url $scheme://$http_host$request_uri;
		auth_request_set $user $upstream_http_remote_user;
		auth_request_set $groups $upstream_http_remote_groups;
		proxy_set_header Remote-User $user;
		proxy_set_header Remote-Groups $groups;
		error_page 401 =302 https://auth.YOURDOMAIN.COM/?rd=$target_url; #change YOURDOMAIN.COM to your domain
 
		client_body_buffer_size 128k;
 
		proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
 
		send_timeout 5m;
		proxy_read_timeout 360;
		proxy_send_timeout 360;
		proxy_connect_timeout 360;
 
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Forwarded-Host $http_host;
		proxy_set_header X-Forwarded-Uri $request_uri;
		proxy_set_header X-Forwarded-Ssl on;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
		proxy_redirect  http://  $scheme://;
		proxy_http_version 1.1;
		proxy_set_header Connection "";
		proxy_cache_bypass $cookie_session;
		proxy_no_cache $cookie_session;
		proxy_buffers 64 256k;
 
		set_real_ip_from 192.168.1.0/16;
		real_ip_header X-Forwarded-For;
		real_ip_recursive on;
 
    }

Sarnog avatar Feb 16 '23 14:02 Sarnog