Setting Auth Tokens in Spotify iOS SDK

Viewed 960

The Spotify iOS SDK is all in objective-c and as of today, it looks like any request using the SDK requires a token. When I try to search for a song, I get this error:

["error": {
    message = "No token provided";
    status = 401;
}]

Here is my appDelegate code:

var auth = SPTAuth()
var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    //Neccessary Spotify stuff
    auth.redirectURL = URL(string: "my_redirect_url")
    auth.sessionUserDefaultsKey = "current session"

    FIRApp.configure()

    window = UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    window?.rootViewController = CustomTabBarController()

    return true
}

// 1
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
    // 2- check if app can handle redirect URL
    if auth.canHandle(auth.redirectURL) {
        // 3 - handle callback in closure
        auth.handleAuthCallback(withTriggeredAuthURL: url, callback: { (error, session) in
            // 4- handle error
            if error != nil {
                print("error!")
            }
            // 5- Add session to User Defaults
            let userDefaults = UserDefaults.standard
            let sessionData = NSKeyedArchiver.archivedData(withRootObject: session as Any)
            userDefaults.set(sessionData, forKey: "SpotifySession")
            userDefaults.synchronize()
            // 6 - Tell notification center login is successful
            NotificationCenter.default.post(name: Notification.Name(rawValue: "loginSuccessfull"), object: nil)
        })
        return true
    }
    return false
}

How do I set the token in Swift?

2 Answers

In your AppDelegate:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

            let auth: SPTAuth = SPTAuth.defaultInstance()
            auth.clientID = "Your-Client-Id"
            auth.redirectURL = URL(string: "Your-Callback-URL")
            auth.sessionUserDefaultsKey = "current session"

            return true
  }

  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        let auth:SPTAuth = SPTAuth.defaultInstance()

        let authCallback: SPTAuthCallback = { error, session in
            if let error = error {
                print(error.localizedDescription)
                return
            }
            auth.session = session

            NotificationCenter.default.post(name: NSNotification.Name("sessionUpdated"), object: nil)
        }

        if auth.canHandle(url) {
            auth.handleAuthCallback(withTriggeredAuthURL: url, callback: authCallback)
            return true
        }

        return false
  }

In your initial View Controller, your login method supposed to be like this:

func loginToSpotify {
        let auth:SPTAuth = SPTAuth.defaultInstance()

//check if first time login

        if auth.session != nil {
            if auth.session.isValid() {
                //to your search page
                return
            }
//refresh token
            renewTokenAndShowSearchVC()
            return
        }

        if SPTAuth.supportsApplicationAuthentication() {
            UIApplication.shared.open(auth.spotifyAppAuthenticationURL(), options: [:], completionHandler: nil)
        } else {
            let safari = SFSafariViewController(url: auth.spotifyWebAuthenticationURL())
            present(safari, animated: true, completion: nil)
        }
    }

func renewTokenAndShowSearchVC() {

        print("Refreshing token...")

        let auth:SPTAuth = SPTAuth.defaultInstance()
        auth.renewSession(auth.session) { (error, session) in
            auth.session = session

            if let error = error {
                print("Refreshing token failed.")
                print(error.localizedDescription)
                return
            }
            //to your search page
        }
    }

then.. somewhere in your View Controller or Model View, you get the token by calling accessToken from SPTSession, for example if you want to search a track (name, artist, and album):

   struct Track: {
            let name: String
            let artist: String
            let album: String

            init(name: String, artist: String, album: String) {
                self.name = name
                self.artist = artist
                self.album = album
            }
        }

     func search(query: String, callback: @escaping ([Track]) -> Void) -> Void {

            let auth: SPTAuth = SPTAuth.defaultInstance()
            let token = auth.session.accessToken

            SPTSearch.perform(withQuery: query, queryType: .queryTypeTrack, accessToken: token, market: "Country_Code") { (error, result) in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }

                if let listPage = result as? SPTListPage, 
                let items = listPage.items as? [SPTPartialTrack], 
                let artist = items.first?.artists.first as? SPTPartialArtist {

                     let tracks = items.compactMap({ (pTrack) -> Track in

                            let name: String = pTrack.name
                            let artist: String = artist.name
                            let album: String = pTrack.album.name

                            return Track(name: name , artist: artist, album: album)
                        })

                        callback(tracks)
                    }
                }
            }
Related