David Chopin
David Chopin

Reputation: 3064

Spotify SessionManager continually failing with error "invalid_grant"

What I'm trying to do: I am implementing the Spotify SDK into my iOS project. I am successfully receiving access tokens for Spotify's API as I am able to do things like search artists, search songs, and view playlists using said API.

The one thing I am struggling to do is play music with the SDK. I have a button that, upon clicking, I want the following flow to happen:

I request Spotify access by doing the following function and using the following Session Manager:

let SpotifyClientID = "###"
let SpotifyRedirectURL = URL(string: "bandmate://")!

lazy var configuration = SPTConfiguration(
    clientID: SpotifyClientID,
    redirectURL: SpotifyRedirectURL
)

lazy var sessionManager: SPTSessionManager = {
    if let tokenSwapURL = URL(string: "https://bandmateallcaps.herokuapp.com/api/token"),
        let tokenRefreshURL = URL(string: "https://bandmateallcaps.herokuapp.com/api/refresh_token") {
        configuration.tokenSwapURL = tokenSwapURL
        configuration.tokenRefreshURL = tokenRefreshURL
        configuration.playURI = ""
    }
    let manager = SPTSessionManager(configuration: configuration, delegate: self)
    return manager
}()

func requestSpotifyAccess() {
    let requestedScopes: SPTScope = [.appRemoteControl, .userReadPrivate]
    self.sessionManager.initiateSession(with: requestedScopes, options: .default)
}

Upon initiation of a SPTSession, I want to connect my remote:

lazy var appRemote: SPTAppRemote = {
    let appRemote = SPTAppRemote(configuration: configuration, logLevel: .debug)
    appRemote.delegate = self
    return appRemote
}()

func sessionManager(manager: SPTSessionManager, didInitiate session: SPTSession) {
    self.appRemote.connectionParameters.accessToken = session.accessToken
    self.appRemote.connect()
}

Upon app connection, I want to play the ID of a Spotify track that is declared globally:

var pendingSpotifyId: String!

func appRemoteDidEstablishConnection(_ appRemote: SPTAppRemote) {
    print("connected")

    self.appRemote.playerAPI!.delegate = self
    self.appRemote.playerAPI!.subscribe(toPlayerState: { (result, error) in

        if let error = error {
            debugPrint(error.localizedDescription)
        } else if self.pendingSpotifyId != nil {
            self.appRemote.playerAPI!.play(self.pendingSpotifyId, callback: { (any, err) in
                self.pendingSpotifyId = nil
            })
        }
    })
}

My problem: This flow is broken up as any time I try to initiate a session, sessionManager(manager: SPTSessionManager, didFailWith error: Error) is always called returning the following error: Error Domain=com.spotify.sdk.login Code=1 "invalid_grant" UserInfo={NSLocalizedDescription=invalid_grant}

I need the session to initiate successfully so that sessionManager(manager: SPTSessionManager, didInitiate session: SPTSession) can be called and I can connect my remote and, ultimately, play my Spotify track.

What I've tried: I have ensured a number of things:

  1. Ensured the state of the Spotify app in the background on the user's device is playing (per this ticket: https://github.com/spotify/ios-sdk/issues/31)
  2. Ensured that the correct scopes are in place when receiving an access token. Returned JSON looks something like:

    {"access_token":"###","token_type":"Bearer","expires_in":3600,"refresh_token":"###","scope":"app-remote-control user-read-private"}

Things I'm suspicious of: I am unaware if my token swap via Heroku is being done correctly. This is the only reason I can think of as to why I would be getting this issue. If I am able to use the Spotify API, is this evidence enough that my token swap is being done correctly? (I suspect it is)

Upvotes: 1

Views: 1401

Answers (1)

Roman Dzięcioł
Roman Dzięcioł

Reputation: 206

Here's what we found out, hope it will help:

  1. The SpotifySDK tutorial doesn't mention that Bundle ID and App Callback URL must precisely match across App Info.plist, source code, Spotify App Dashboard and Heroku Env Vars. The Bundle ID used must match your application Bundle ID.
  2. The App Callback URL must not have empty path, ie: my-callback-scheme://spotify-login-callback
  3. When using both Web Spotify SDK and iOS Framework Spotify SDK in app, take care that only one of them performs auth. Otherwise the App Callback URL will be called twice resulting in error.
  4. The Spotify configuration.playURI may need to be set to empty string rather than nil. Sample app has a note on it.
  5. It's best to have only one instance of object managing Spotify auth in the app. Otherwise ensuring that the correct object is called from the AppDelegate open url method can be tricky.

Upvotes: 4

Related Questions