Single Sign-On using Spotify Android application with a fallback to Spotify Accounts Service in a Custom Tab
+
+ SDK will try to fetch the authorization code/access token using the Spotify Android client.
+ If Spotify is not installed on the device, SDK will fallback to the Custom Tabs based authorization
+ and open Spotify Accounts Service in a dialog.
+ After authorization flow is completed, result is returned to the activity
+ that invoked the AuthorizationClient
.
+
+ If Spotify is installed on the device, SDK will connect to the Spotify client and
+ try to fetch the authorization code/access token for current user.
+ Since the user is already logged into Spotify they don't need to fill their username and password.
+ If the SDK application requests scopes that have not been approved, the user will see
+ a list of scopes and can choose to approve or reject them.
+
+ If Spotify is not installed on the device, SDK will open a dialog and load Spotify Accounts Service
+ into a Custom Tab. User will have to enter their username and password to login to Spotify.
+ They will also need to approve any scopes the the SDK application requests and that they
+ haven't approved before.
+
+ In both cases (SSO and Custom Tab fallback) the result of the authorization flow will be returned
+ in the onActivityResult
method of the activity that initiated it.
+
+
+ For login flow to work, LoginActivity needs to be added to the AndroidManifest.xml
:
+
+
+ <activity
+ android:name="LoginActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+
+
+ // Code called from an activity
+ private static final int REQUEST_CODE = 1337;
+
+ final AuthorizationRequest request = new AuthorizationRequest.Builder(CLIENT_ID, AuthorizationResponse.Type.TOKEN, REDIRECT_URI)
+ .setScopes(new String[]{"user-read-private", "playlist-read", "playlist-read-private", "streaming"})
+ .build();
+
+ AuthorizationClient.openLoginActivity(this, REQUEST_CODE, request);
+
+
+ It is also possible to use LoginActivity
from other component such as Fragments:
+
+ // To start LoginActivity from a Fragment:
+ Intent intent = AuthorizationClient.createLoginActivityIntent(getActivity(), request);
+ startActivityForResult(intent, REQUEST_CODE);
+
+ // To close LoginActivity
+ AuthorizationClient.stopLoginActivity(getActivity(), REQUEST_CODE);
+
+
+ To process the result activity needs to override onActivityResult
callback
+
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ super.onActivityResult(requestCode, resultCode, intent);
+
+ // Check if result comes from the correct activity
+ if (requestCode == REQUEST_CODE) {
+ AuthorizationResponse response = AuthorizationClient.getResponse(resultCode, intent);
+ switch (response.getType()) {
+ // Response was successful and contains auth token
+ case TOKEN:
+ // Handle successful response
+ String token = response.getAccessToken();
+ break;
+
+ // Auth flow returned an error
+ case ERROR:
+ // Handle error response
+ break;
+
+ // Most likely auth flow was cancelled
+ default:
+ // Handle other cases
+ }
+ }
+ }
+
+
+
+
+
+ In this scenario the SDK creates an intent that will open the browser. Authorization
+ takes part in the browser (not in the SDK application). After authorization is completed
+ browser redirects back to the SDK app.
+
+
+ // Code called from an activity
+ final AuthorizationRequest request = new AuthorizationRequest.Builder(CLIENT_ID, AuthorizationResponse.Type.TOKEN, REDIRECT_URI)
+ .setScopes(new String[]{"user-read-private", "playlist-read", "playlist-read-private", "streaming"})
+ .build();
+
+ AuthorizationClient.openLoginInBrowser(this, request);
+
+
+ To receive the result AndroidManifest.xml
must contain following:
+
+
+ // The activity that should process the response from auth flow
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:launchMode="singleInstance" >
+ <intent-filter>
+ // Any other intent filters that this activity requires
+ </intent-filter>
+
+ // An intent filter that will receive the response from the authorization service
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+
+ <category android:name="android.intent.category.DEFAULT"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+
+ // this needs to match the scheme and host of the redirect uri
+ <data
+ android:host="callback"
+ android:scheme="yourcustomprotocol"/>
+ </intent-filter>
+ </activity>
+
+
+ To process the result the receiving activity (MainActivity
in this example) needs to override one of its
+ callbacks. With launch mode set to singleInstance
this callback is onNewIntent
:
+
+
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ Uri uri = intent.getData();
+ if (uri != null) {
+ AuthorizationResponse response = AuthorizationResponse.fromUri(uri);
+ switch (response.getType()) {
+ // Response was successful and contains auth token
+ case TOKEN:
+ // Handle successful response
+ String token = response.getAccessToken();
+ break;
+
+ // Auth flow returned an error
+ case ERROR:
+ // Handle error response
+ break;
+
+ // Most likely auth flow was cancelled
+ default:
+ // Handle other cases
+ }
+ }
+ }
+
+
+