Hello,
For information and to avoid duplicates, I will have to launch Claude on a Daikin integration tomorrow
The video on developing an external integration really gave me the urge to get started
I might also need testers
I’ll keep you posted
It’s developed and available only for testing at the moment:
Build and publish image #1
However, I’ll wait for the next version to test authentication after this PR is released:
master ← claude/spotify-https-integration-jv3xnp
ouvert 05:34PM - 03 Aug 26 UTC
### Description
OAuth2 providers now require an HTTPS redirect URI. Spotify [en… forces it since April 2025](https://developer.spotify.com/documentation/web-api/concepts/redirect_uri): only `https://` is accepted, plus the loopback literals `http://127.0.0.1:PORT` and `http://[::1]:PORT` — `localhost` is refused, and so is any LAN address.
The frontend built `redirect_uri` from `window.location.origin`, so anyone reaching Gladys at `http://192.168.1.50:1443` — most self-hosted users — got `redirect_uri: Not matching configuration` and simply could not connect a Spotify account.
`redirect_uri` is now the fixed HTTPS page `https://my.gladysassistant.com/redirect/oauth` (static site, source in [GladysAssistant/my.gladysassistant.com](https://github.com/GladysAssistant/my.gladysassistant.com)). The address to come back to travels in the OAuth2 `state`, the only parameter a provider hands back untouched:
```js
state = base64url(JSON.stringify({ v: 1, origin, path, state: '<the integration state>' }));
```
The redirect page unwraps it, shows the visitor which instance they are about to return to, and bounces them there with every provider parameter forwarded. Nothing runs server-side there: no authorization code, token or credential ever reaches a Gladys server. It only redirects to an HTTPS origin or to a plain-HTTP origin that can exist solely on the visitor's own network, always behind an explicit click.
This is the same approach Home Assistant takes with `my.home-assistant.io`.
**Integrations need no change.** They already receive the `redirect_uri` and use it as-is (`onOAuthAuthorizeUrl(key, redirectUri)`), and they get their own `state` back to verify. The server is untouched too — the whole change is in the frontend.
Also in this PR:
- the configuration screen now **shows the redirect URI to copy** into the provider's developer application, with a copy button. Guessing it wrong is what people were stuck on in the forum thread.
- users who already serve Gladys over HTTPS can **opt out** and use their own address instead (offered only when the frontend is served over HTTPS, remembered in `localStorage`).
- the `redirect_uri` used is stored alongside the oauth2 key so the callback sends back exactly the same one — the provider compares it byte for byte at token exchange.
**One behaviour change for integration authors**: the `state` becomes mandatory in the authorize URL. Without it there is no way home, so an integration that omits it now gets an explicit error message instead of failing silently. `docs/specs/external-integrations.md` is updated accordingly.
A side benefit worth knowing: a single URL now has to be declared at the provider, whether the user reaches Gladys locally or through Gladys Plus. Before, the redirect URI depended on how you were browsing.
## Forum
Forum: https://community.gladysassistant.com/t/impossible-de-creer-le-plugin-spotify/10439
### Checklist
- [ ] Tests pass: `cd server && npm run coverage` (Codecov requires 100% coverage on changed lines) and Cypress (`npm run cypress:run`) if the UI changed
- [x] Linter and prettier pass on both front and server (`npm run eslint`, `npm run prettier`)
- [x] No undocumented breaking change
On the first box, being explicit about what was and was not run:
- No server code changed, so the server suite is untouched by this PR.
- Cypress was not run — it needs a live Gladys stack with an installed external integration.
- `npm run build`, `npm run eslint` (0 errors), `npm run prettier-check` and `npm run compare-translations` all pass on the front.
- The wrapping was verified end to end against the redirect page: a realistic Spotify authorize URL goes through `wrapAuthorizeUrl()`, then through the page's `decodeWrappedState()` / `buildRedirectUrl()`, and comes back as `http://192.168.1.50:1443/dashboard/.../oauth-callback?code=…&state=<the integration state>` with `client_id`, `scope` and `redirect_uri` untouched. The redirect page itself has 15 unit tests covering the origin and path checks.
- The front has no unit test runner today, so `front/src/utils/oauth.js` ships without tests. Happy to add one if you want a runner introduced.
---
_Generated by [Claude Code](https://claude.ai/code/session_0197FhTmFSecAUY5CqCYG7vN)_
## Summary by CodeRabbit
- **New Features**
- Added copyable HTTPS redirect URIs for OAuth setup.
- Added support for instance-specific redirect addresses when available, with a user-selectable option.
- Improved OAuth callback handling with stronger security-state validation.
- Added clearer connection guidance and invalid-state error messages.
- Added English, German, and French localization updates.
- **Documentation**
- Expanded OAuth guidance covering redirect setup, local HTTP instances, callback routing, and token handling.
@pierre-gilles Any idea when the next version with the redirect page will be released?
Thanks
I’m trying to do that tonight
Thanks
OAuth2 works well and I was able to run some tests
There are still a few bugs being fixed, but I’m waiting for the next Claude reset to continue I’ve used up all my tokens
I should be able to release a stable version tomorrow