Skip to content

Adding support for cloudflare access token#445

Open
pepitoria wants to merge 1 commit intogotify:masterfrom
pepitoria:cloudflare-access-token-support
Open

Adding support for cloudflare access token#445
pepitoria wants to merge 1 commit intogotify:masterfrom
pepitoria:cloudflare-access-token-support

Conversation

@pepitoria
Copy link
Copy Markdown

Add Cloudflare Access Token Headers Support

Summary

  • Add support for Gotify servers behind Cloudflare Access by allowing users to configure CF-Access-Client-Id and CF-Access-Client-Secret headers
  • CF Access credentials can be configured from the login screen's Advanced Dialog (required before login) and the Settings screen (after login)
  • When enabled, headers are attached to all HTTP requests: API calls, WebSocket connections, and image loading

Motivation

Users whose Gotify servers are protected by Cloudflare Access could not use the Android app at all — the login request itself would be blocked without the CF headers. This change adds CF Access configuration to the Advanced Dialog on the login screen, following the same pattern used for SSL/certificate settings.

Changes

New files

File Description
CfAccessSettings.kt Data class holding enabled, clientId, and clientSecret
api/CloudflareAccessInterceptor.kt OkHttp interceptor that adds CF-Access-Client-Id and CF-Access-Client-Secret headers to every request

Modified files

File Description
Settings.kt Added cfAccessEnabled, cfAccessClientId, cfAccessClientSecret properties, cfAccessSettings() helper, and cleanup in clear()
login/AdvancedDialog.kt Added Cloudflare Access section: enable checkbox and two text inputs for Client ID and Client Secret
res/layout/advanced_settings_dialog.xml Added UI elements: divider, checkbox, and two TextInputLayout fields for CF credentials
login/LoginActivity.kt Added temporary CF state variables, tempCfAccessSettings() helper, passes CF settings to ClientFactory during URL check and login, persists credentials on successful login
api/ClientFactory.kt Added cfAccessSettings parameter to defaultClient(), versionApi(), basicAuth(), and unauthorized(); applies interceptor when enabled
service/WebSocketConnection.kt Accepts CfAccessSettings parameter, applies interceptor to the OkHttpClient used for WebSocket connections
service/WebSocketService.kt Passes settings.cfAccessSettings() when creating WebSocketConnection
CoilInstance.kt Applies interceptor to image loading OkHttpClient; includes CfAccessSettings in cache key to invalidate when credentials change
res/xml/root_preferences.xml Added "Cloudflare Access" preference category with a switch and two EditTextPreference fields (dependency-linked to the switch)
settings/SettingsActivity.kt Syncs CF preferences with Settings class (custom SharedPreferences), triggers WebSocket restart on change
res/values/strings.xml Added all Cloudflare Access string resources (keys, titles, summaries, hints)

How it works

  1. Before login: User opens the Advanced Dialog (gear icon next to "Check URL"), enables "Cloudflare Access", and enters their Client ID and Secret. These are used for the URL check and login requests.
  2. On successful login: CF Access credentials are persisted to the app's SharedPreferences via the Settings class.
  3. After login: CF headers are automatically applied to all API calls (ClientFactory), WebSocket connections (WebSocketConnection), and image loading (CoilInstance).
  4. Settings screen: Users can view, edit, or disable CF Access from a dedicated "Cloudflare Access" section. Changes trigger a WebSocket reconnection.

Test plan

  • Build succeeds: ./gradlew assembleDebug
  • Open login screen, tap Advanced Dialog, verify Cloudflare Access section appears with checkbox and hidden fields
  • Enable checkbox, verify Client ID and Client Secret fields appear
  • Enter CF credentials, check URL against a CF-protected Gotify server, verify version check succeeds
  • Log in successfully, verify CF credentials are persisted
  • After login, open Settings, verify "Cloudflare Access" section shows saved values
  • Toggle CF Access off in Settings, verify WebSocket reconnects without CF headers
  • Verify images load correctly with CF headers enabled

@pepitoria
Copy link
Copy Markdown
Author

Hi guys, I have opened this PR out of my own need. I have my gotify server exposed through cloudflare tunnels but since for the paranoid of us that is not enough to be comfy, I added access control from cloudflare.

This PR adds that in the app to handle the headers needed for the app to work. I also added a cloudflare-tunnel-access-setup.md in the root of the project that I really do not intent to make it to the app code in master but your you guys (maintainers) to check out if you want.

Disclaimer: I used claude code to implement this feature but I have also have 15 years of professional android development experience and I have reviewed all changes so I hope this is not an issue.

@jmattheis
Copy link
Copy Markdown
Member

Have you considered using mutual TLS? https://developers.cloudflare.com/learning-paths/mtls/mtls-cloudflare-access/

This should be more secure than just some extra secrets in the headers and is already supported by the app.

@pepitoria
Copy link
Copy Markdown
Author

to be honest, no, I did not considered it because I did not know about them! I will check it out at some point, for now I have the access token working with my gotify domain in cloudflare and the app seems to be running fine (I installed on device from android studio).

Thanks for the suggestion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants