Peter-Schorn / SpotifyAPI

A Swift library for the Spotify web API. Supports all endpoints.
https://peter-schorn.github.io/SpotifyAPI/documentation/spotifywebapi
MIT License
251 stars 32 forks source link

Playlist creation can fail when using family plan accounts #41

Closed bbauman1 closed 1 year ago

bbauman1 commented 1 year ago

I have an app that allows for creation of playlists and have some users reporting errors that they are receiving this message when attempting to create a playlist (I'm showing the error.localizedDescription in an alert)

You cannot create a playlist for another user (403)

I've chatted with some users and every case that this happens is for people with premium family plan accounts (Spotify Duo or 4-person plans). It appears that either their access token or URI is for the main family member's account while the other is the actual account. Some kind of mismatch resulting in this error. Have you seen anything like this before?

Peter-Schorn commented 1 year ago
You cannot create a playlist for another user (403)

It appears that either their access token or URI is for the main family member's account while the other is the actual account.

I have not encountered this error before, but this is exactly what I would expect. The user that the access token was obtained on behalf of must be the same user whose URI is passed in to the method for creating a playlist. In other words, you should forget about the existence of family plan accounts entirely in this context. Family plan accounts are separate just like any other accounts are separate for the purposes of using the Web API.

It's common for end users with multiple accounts to be confused about which account the access token was obtained on behalf of. If you are authorizing using the Authorization Code Flow, you can set the showDialog parameter of the AuthorizationCodeFlowManager.makeAuthorizationURL(redirectURI:showDialog:state:scopes:) method to true so that users who are already signed in to one account in their browser have a chance to sign in to another account before proceeding with the rest of the authorization process.

To verify which user the access token was issued for, use the SpotifyAPI.currentUserProfile() method. The user URI returned by this method must be the same URI passed in to the method for creating a playlist.

bbauman1 commented 1 year ago

To verify which user the access token was issued for, use the [SpotifyAPI.currentUserProfile()](https://spotify-api-docs.herokuapp.com/documentation/spotifywebapi/spotifyapi/currentuserprofile()) method. The user URI returned by this method must be the same URI passed in to the method for creating a playlist.

Currently I'm using a copy of your example app Spotify class and providing the URI from currentUser.uri, example here, which is backed by currentUserProfile. I also have showDialog set to true.

It seems there's still a way that the URI from currentUserProfile is different than the one the access token is granted for. I'm authorizing for these scopes

scopes: [
    .playlistModifyPrivate,
    .playlistModifyPublic,
]
Peter-Schorn commented 1 year ago

It seems there's still a way that the URI from currentUserProfile is different than the one the access token is granted for.

I think what's more likely is that there's a bug in the Spotify class in which Spotify.currentUser is not always kept up to date with the currently authorized user—as opposed to there being a problem with the web API itself.

Notice that retrieveCurrentUser, which is called by Spotify.authorizationManagerDidChange(), only updates Spotify.currentUser if this property is nil (unless the onlyIfNil parameter is set to false). And Spotify.currentUser is only set to nil after SpotifyAPI.authorizationManager.deauthorize() is called in Spotify. authorizationManagerDidDeauthorize.

Therefore, if you authorize for one user, and then authorize for another without calling SpotifyAPI.authorizationManager.deauthorize() first, Spotify.currentUser will still be set to the first user you authorized for.

In my app, it is not possible to authorize for another user without first tapping the Logout button, which does call SpotifyAPI.authorizationManager.deauthorize(), thereby setting Spotify.currentUser to nil, so this bug cannot occur.

If you're still convinced that the problem is with the web API itself, try changing the call to self.retrieveCurrentUser() in Spotify.authorizationManagerDidChange() to self.retrieveCurrentUser(onlyIfNil: false) so that Spotify.currentUser is updated anytime the authorization information changes. This will lead to redundant calls to SpotifyAPI.currentUserProfile() when merely the access token is refreshed (because this also causes Spotify.authorizationManagerDidChange() to be called).

bbauman1 commented 1 year ago

I also have a logout button that calls daeuthorize. I can make the change to call currentUserProfile() when creating a playlist and then see if that fixes the issue for these users. I'll report back in 2-3 days

Peter-Schorn commented 1 year ago

You may simply want to call currentUserProfile() directly before creating the playlist to confirm this is not an issue with the web API.

bbauman1 commented 1 year ago

Yeah thats the change I'm going to make. Its working for me, but I don't have a repro of these shared family accounts to try with

bbauman1 commented 1 year ago

I put out an app update and 2 users let me know the issue is still happening for them. I'm calling currentUserProfile() directly before createPlaylist() and passing in the URI. Do you think its possible for it to be an issue on Spotify's end? I don't think this should be scopes related.

Peter-Schorn commented 1 year ago

It's certainly possible. I've encountered bugs in the web API before. I would recommend that you install logging facilities in your app so that you can know for sure what's going on. I have a family plan, so I can try to reproduce the bug. Can you send me a link to your app?

bbauman1 commented 1 year ago

https://apps.apple.com/us/app/lineupsupply-playlist-maker/id1631703551

I don't think its affecting every family plan account from what I can tell, but for those who are affected it happens 100% of the time when creating a playlist

Peter-Schorn commented 1 year ago

I tested your app with my family plan member account and my Dad's family plan manager account and I could not reproduce the bug.

bbauman1 commented 1 year ago

Appreciate you testing it. I have some Spotify engineers on Twitter I'll try reaching out to them and see if they are aware of anything. Might have to create a family plan myself as well. I guess I can close this unless you have other ideas

Peter-Schorn commented 1 year ago

I suggest that you post about it at the Spotify Developer Forums.

Peter-Schorn commented 1 year ago

See #42. This could be the cause of the issue. Test your app with a user with underscores in the user ID (not the display name). (Edit: the bug has been fixed.)

bbauman1 commented 1 year ago

@Peter-Schorn thank you

bbauman1 commented 1 year ago

Can confirm that this fixed the issue