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:
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
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)
audiobookshelf://oauth
This link will send a message to the app including state and code variable generated by Authentik
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>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 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:
master← Head:oauth2-support📝 Commits (10+)
e521ddfOAuth2 Support8b631f7oauth2 support on Androidd613d89Fix host path extra port, fix formatting737d8f1Move appUrlOpen listener to plugin and listen for eventBus event6c88337oauth2: Force HTTPS, check state2984398ServerConnect: Improve connect flow8d8782aoauth2: Implement PKCE30d4e70Merge branch 'master' into oauth2-support945baa2Connect: Check if audiobookshelf and check for version1a6b716oauth2: 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
Should work on Android, too. But needs testing (I dont have an dev env for that)(Testing done successfully)It works this way:
audio.example.com/auth/openid&redirect_uri=audiobookshelf://oauthaudio.example.com/auth/openid/callback. Saving the Cookie is automatically done withCapacitorHttp.getas it uses a native function, it won't work in any case withfetchoraxiosaudio.example.com/auth/openid/callbackwith the state and the code (and the cookie from the first request bc of passport)Error handling is also done:
I used
App.addListeneron top inServerConnectForm.vue. I'm not really familiar with Vue so I saved thethispointer of the component simply in the variableserverConnectForm. 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 theelseshould 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.