[PR #906] [MERGED] OAuth2 Support #1476

Closed
opened 2026-04-24 23:58:44 +02:00 by adam · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/advplyr/audiobookshelf-app/pull/906
Author: @Sapd
Created: 10/8/2023
Status: Merged
Merged: 11/11/2023
Merged by: @advplyr

Base: masterHead: oauth2-support


📝 Commits (10+)

  • e521ddf OAuth2 Support
  • 8b631f7 oauth2 support on Android
  • d613d89 Fix host path extra port, fix formatting
  • 737d8f1 Move appUrlOpen listener to plugin and listen for eventBus event
  • 6c88337 oauth2: Force HTTPS, check state
  • 2984398 ServerConnect: Improve connect flow
  • 8d8782a oauth2: Implement PKCE
  • 30d4e70 Merge branch 'master' into oauth2-support
  • 945baa2 Connect: Check if audiobookshelf and check for version
  • 1a6b716 oauth2: Add comments

📊 Changes

12 files changed (+537 additions, -125 deletions)

View changed files

📝 android/app/capacitor.build.gradle (+1 -1)
📝 android/app/src/debug/res/values/strings.xml (+1 -1)
📝 android/app/src/main/assets/capacitor.plugins.json (+4 -4)
📝 android/app/src/main/res/values/strings.xml (+1 -1)
📝 android/capacitor.settings.gradle (+3 -3)
📝 components/connection/ServerConnectForm.vue (+461 -74)
📝 ios/App/App/Info.plist (+11 -0)
📝 ios/App/Podfile (+1 -1)
📝 ios/App/Podfile.lock (+28 -22)
📝 package-lock.json (+16 -16)
📝 package.json (+2 -2)
📝 plugins/init.client.js (+8 -0)

📄 Description

This PR Provides oauth2 support

It works out-of-the-box with the current changes in https://github.com/advplyr/audiobookshelf/pull/1636

  • Fully works on iOS and Android
  • Should work on Android, too. But needs testing (I dont have an dev env for that) (Testing done successfully)
  • It should - in theory - also work with Google and co, but needs testing. If there is a error I would check if the callback URLs are correct as first step

It works this way:

  1. oauthRequest
    • API request to audio.example.com/auth/openid
    • This will try to redirect to the idp/authentik. Instead of redirecting Im catching it and open this link in a browser. Also Im patching the redirect_uri parameter to &redirect_uri=audiobookshelf://oauth
    • Also what its very important (and required by passport - oauth only requires it as GET parameter instead in a Session), it will generate a state variable and also save it into a Cookie. This Cookie needs to be sent in the request later to audio.example.com/auth/openid/callback. Saving the Cookie is automatically done with CapacitorHttp.get as it uses a native function, it won't work in any case with fetch or axios
  2. Browser.Open
    • This is the redirect to Authentik, sending also the openid parameters and additionally the same state variable from above. The user logs in. In any case authentik will then redirect to audiobookshelf://oauth and pass along a code and state parameter via GET parameters
    • Cookies are not required to be saved or passed (oauth works completely without session but just GET parameters)
  3. audiobookshelf://oauth
    • This link will send a message to the app including state and code variable generated by Authentik
  4. oauthExchangeCodeForToken
    • This calls audio.example.com/auth/openid/callback with the state and the code (and the cookie from the first request bc of passport)
    • Browser is closed
    • Token is returned and then handled like with user/pass login

Error handling is also done:

  • this.showAuth = true is not required to be set on error I noticed
  • My error handling might not be consistent with the existing code and the toasts might need translation
  • The error handling in the backend is currently not sufficient. On a state error the message will be just forbidden without any logs (will post details in the other PR). Can be important when you test google integration or so

I used App.addListener on top in ServerConnectForm.vue. I'm not really familiar with Vue so I saved the this pointer of the component simply in the variable serverConnectForm. Maybe there is a better way. Also in the function I catched for other not implemented URLs, given that the function can be called multiple times this catch might not make sense at this point (so probably either the else should be removed or the function should be centrally moved somewhere else in a routing file).


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/advplyr/audiobookshelf-app/pull/906 **Author:** [@Sapd](https://github.com/Sapd) **Created:** 10/8/2023 **Status:** ✅ Merged **Merged:** 11/11/2023 **Merged by:** [@advplyr](https://github.com/advplyr) **Base:** `master` ← **Head:** `oauth2-support` --- ### 📝 Commits (10+) - [`e521ddf`](https://github.com/advplyr/audiobookshelf-app/commit/e521ddfab6933cef5823bc2b8320c28d32c7da67) OAuth2 Support - [`8b631f7`](https://github.com/advplyr/audiobookshelf-app/commit/8b631f7860a25f7075eb1a23ac643f9b188e7892) oauth2 support on Android - [`d613d89`](https://github.com/advplyr/audiobookshelf-app/commit/d613d8954d492cda00d370430462573485a6fe01) Fix host path extra port, fix formatting - [`737d8f1`](https://github.com/advplyr/audiobookshelf-app/commit/737d8f19b3c0ad88f18e455a0b1623b94ee0c058) Move appUrlOpen listener to plugin and listen for eventBus event - [`6c88337`](https://github.com/advplyr/audiobookshelf-app/commit/6c8833718008958204c24490ec7025b96e9a7a91) oauth2: Force HTTPS, check state - [`2984398`](https://github.com/advplyr/audiobookshelf-app/commit/29843980512014527970572091be2c5558493a6c) ServerConnect: Improve connect flow - [`8d8782a`](https://github.com/advplyr/audiobookshelf-app/commit/8d8782a5a9960a79d3f255642fdec8d057682a18) oauth2: Implement PKCE - [`30d4e70`](https://github.com/advplyr/audiobookshelf-app/commit/30d4e709f00f4cb837c26c228ed0a0d4e5bd7e3d) Merge branch 'master' into oauth2-support - [`945baa2`](https://github.com/advplyr/audiobookshelf-app/commit/945baa24f00db2ae2914ff9e835ee1477decfbb3) Connect: Check if audiobookshelf and check for version - [`1a6b716`](https://github.com/advplyr/audiobookshelf-app/commit/1a6b716046517cc8d94007207b21e9cd0f9318dd) oauth2: Add comments ### 📊 Changes **12 files changed** (+537 additions, -125 deletions) <details> <summary>View changed files</summary> 📝 `android/app/capacitor.build.gradle` (+1 -1) 📝 `android/app/src/debug/res/values/strings.xml` (+1 -1) 📝 `android/app/src/main/assets/capacitor.plugins.json` (+4 -4) 📝 `android/app/src/main/res/values/strings.xml` (+1 -1) 📝 `android/capacitor.settings.gradle` (+3 -3) 📝 `components/connection/ServerConnectForm.vue` (+461 -74) 📝 `ios/App/App/Info.plist` (+11 -0) 📝 `ios/App/Podfile` (+1 -1) 📝 `ios/App/Podfile.lock` (+28 -22) 📝 `package-lock.json` (+16 -16) 📝 `package.json` (+2 -2) 📝 `plugins/init.client.js` (+8 -0) </details> ### 📄 Description This PR Provides oauth2 support It works out-of-the-box with the current changes in https://github.com/advplyr/audiobookshelf/pull/1636 * Fully works on iOS and Android * ~~Should work on Android, too. But needs testing (I dont have an dev env for that)~~ (Testing done successfully) * It should - in theory - also work with Google and co, but needs testing. If there is a error I would check if the callback URLs are correct as first step It works this way: 1. oauthRequest * API request to `audio.example.com/auth/openid` * This will try to redirect to the idp/authentik. Instead of redirecting Im catching it and open this link in a browser. Also Im patching the redirect_uri parameter to `&redirect_uri=audiobookshelf://oauth` * Also what its very important (and required by passport - oauth only requires it as GET parameter instead in a Session), it will generate a state variable and also save it into a Cookie. This Cookie needs to be sent in the request later to `audio.example.com/auth/openid/callback`. Saving the Cookie is automatically done with `CapacitorHttp.get` as it uses a native function, it won't work in any case with `fetch` or `axios` 2. Browser.Open * This is the redirect to Authentik, sending also the openid parameters and additionally the same state variable from above. The user logs in. In any case authentik will then redirect to audiobookshelf://oauth and pass along a code and state parameter via GET parameters * Cookies are not required to be saved or passed (oauth works completely without session but just GET parameters) 3. audiobookshelf://oauth * This link will send a message to the app including state and code variable generated by Authentik 4. oauthExchangeCodeForToken * This calls `audio.example.com/auth/openid/callback` with the state and the code (and the cookie from the first request bc of passport) * Browser is closed * Token is returned and then handled like with user/pass login Error handling is also done: * this.showAuth = true is not required to be set on error I noticed * My error handling might not be consistent with the existing code and the toasts might need translation * The error handling in the backend is currently not sufficient. On a state error the message will be just forbidden without any logs (will post details in the other PR). Can be important when you test google integration or so I used `App.addListener` on top in `ServerConnectForm.vue`. I'm not really familiar with Vue so I saved the `this` pointer of the component simply in the variable `serverConnectForm`. Maybe there is a better way. Also in the function I catched for other not implemented URLs, given that the function can be called multiple times this catch might not make sense at this point (so probably either the `else` should be removed or the function should be centrally moved somewhere else in a routing file). --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
adam added the pull-request label 2026-04-24 23:58:44 +02:00
adam closed this issue 2026-04-24 23:58:44 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf-app#1476