Issue
I am working on integrating Spotify's OAuth authentication into a web application for mobile users. The goal is to enable users to authenticate via the Spotify mobile app on Android devices, ensuring compatibility with popular browsers like Chrome Mobile and in-app browsers such as those in Instagram, Facebook, and TikTok.
"MY APP" here is the client that requests access to the protected resources (i.e. my web app). I am following the Spotify Authorization Code Flow, and my current implementation is as follows:
const urlQueryParams = '?scope=user-read-email&response_type=code&redirect_uri=[ENCODED_REDIRECT_URI]&state=[STATE]&client_id=[CLIENT_ID]';
onclick: function () {
let url = 'https://accounts.spotify.com/authorize';
url += urlQueryParams;
window.location.href = url;
}
This code works, but it always prompts users to authenticate through the Spotify Auth webpage, even if they have the Spotify app installed and are logged in. This process is inconvenient for mobile users. I saw in similar questions that a redirect from web to app should happen autonomously, provided the user has the app installed, but according to my own testing it doesn't happen for /authorize
page.
For the sake of clarity, let's assume that the Spotify app for Android is always installed and End User is authenticated inside the app.
I've tried the following approach:
const urlQueryParams = '...';
onclick: function () {
let url = 'https://accounts.spotify.com/inapp-authorize';
url += urlQueryParams;
window.location.href = url;
}
This method sometimes behaves like a deep link, opening the Spotify app for Android and redirecting users back to My App if they have previously granted access. It works in Chrome Mobile but not in Instagram's webview. It asks user to login via webpage inside Instagram. Also it stucks on infinite "Loading..." inside Spotify app if users have NOT previously granted access to My App.
I also experimented with an intent://
schema:
const urlQueryParams = '...';
onclick: function () {
let url = 'intent://accounts.spotify.com/inapp-authorize';
url += urlQueryParams + '#Intent;package=com.spotify.music;scheme=spotify;end';
window.location.href = url;
}
This approach always prompts users to continue in the Spotify app, but it leads them to the Home page instead of the Login page.
I am aware of the spotify://
schema for deep linking to albums, artists, and tracks in the Spotify app. However, I'm unsure how to use it to deep link directly to the Auth page in the Spotify app for Android.
I am seeking a reliable solution for authenticating users via the Spotify app across different mobile browsers and in-app webviews. Insights from Spotify engineers or anyone with relevant experience would be highly appreciated.
Here's a minimal reproducible example on jsFiddle. Additional details, such as demo screenshots, can be provided upon request.
Solution
The following URI triggers authorization within the Spotify app when the app is installed, and the browser / user allows opening external apps. In all other cases the browser uses the configured FALLBACK_URL
:
intent://accounts.spotify.com/inapp-authorize?scope=user-read-email&response_type=code&redirect_uri=[ENCODED-REDIRECT_URL]&client_id=[CLIENT-ID]#Intent;scheme=https;package=com.spotify.music;S.browser_fallback_url=[FALLBACK_URL];end
This version differs from the example in the question in two aspects:
- The scheme is
https
instead ofspotify
- The URI defines an intent extra parameter with the name
S.browser_fallback_url
as fallback
Intent Protocol in General
The syntax of the intent URI is (partially) documented in Android Intents with Chrome. While only officially documented for Chrome, the parsing of the URI is actually an Android feature (see the source code of Intent.parseUri). Browser support is not specific to Chrome but implemented in Chromium for Android here. With it, the functionality is by default available on every Chromium-based browser, including WebViews and Android Custom Tabs.
I've tested this with Chrome, Samsung Internet, Firefox, Edge and a WebView. The FALLBACK_URL
is reliably used when the intent cannot be found (i.e.the Android app is not installed), the user disabled opening external apps in the browser settings or the user declines, to load the external app (Firefox and Edge). Support for the intent URL for Firefox and Mozilla's GeckoView can be found here.
I never tested with any of the mentioned in-app browsers. But at least Meta seems to use Chromium as base for their in-app browsers (see here). If developers of Meta shouldn't have explicitly taken measures to disable the feature, intent URIs should also work for Instagram and Facebook in-app browsers. I don't know what TikTok is using as base for their Android app but as both, GeckoView and Chromium are supporting the intent protocol, it is very unlikely that this should not work within the TikTok app (please correct me if I should be wrong)
Spotify Authorization Use Case
The ingredients for the in-app authentication URI can be found in the AndroidManifest.xml file of the Spotify app (this also explains why the scheme has to be https
and not spotify
). Exactly the same activity is also triggered by Spotify's auth-lib for Android apps (see here).
The Spotify app seems to trigger the redirect URL through an intent that contains the ACTION_VIEW
intent action. This opens the URL in the system browser, which may be different from the browser, where the login was triggered (as documented here). Spotify's auth-lib intercepts this by registering a custom protocol and uses this in the redirect URL. I guess this approach will not be possible for a web application. Therefore you either have to put enough state information into the state parameter, so that your app can continue in a new browser instance or you handle the state on the server and display the user a hint, that authorization was successful and (s)he should press the back button to continue in your app.
Answered By - rmunge
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.