/SpotifyAPI

A Swift library for the Spotify web API. Supports all endpoints.

Primary LanguageSwiftMIT LicenseMIT

SpotifyAPI

A Swift library for the Spotify web API

Features

  • Supports all of the Spotify web API endpoints, including playing content, creating playlists, and retrieving albums.
  • Uses Apple's Combine framework, which makes chaining asynchronous requests a breeze
  • Supports three different authorization methods
  • Automatically refreshes the access token when necessary

Read the full documentation and check out this example iOS app and this example command-line app.

Sponsors

Table of Contents

Supported Platforms

  • Swift 5.6+
  • iOS 13+
  • macOS 10.15+
  • tvOS 13+
  • watchOS 6+
  • Linux

Installation

  1. In Xcode, open the project that you want to add this package to.
  2. From the menu bar, select File > Swift Packages > Add Package Dependency...
  3. Paste the URL for this repository into the search field.
  4. Select the SpotifyAPI Library.
  5. Follow the prompts for adding the package.

Quick Start

To get started, go to the Spotify Developer Dashboard and create an app. You will receive a client id and client secret. Then, click on "edit settings" and add a redirect URI. Usually, this should be a custom URL scheme that redirects to a location in your app. DO NOT add a forward-slash to the end of the redirect URI.

The next step is authorizing your app. All requests to the Spotify web API—whether they require authorization scopes or not—require authorization This library supports three authorization methods:

See also Additional Authorization Methods.

When creating an application that uses this library, you will probably want to save the authorization information to persistent storage so that the user does not have to login again every time the application is quit and re-launched. See Saving Authorization Information to Persistent Storage for a guide on how to do this.

Authorizing with the Authorization Code Flow with Proof Key for Code Exchange

Create an instance of SpotifyAPI and assign an instance of AuthorizationCodeFlowPKCEManager to the authorizationManager property:

import SpotifyWebAPI

let spotify = SpotifyAPI(
    authorizationManager: AuthorizationCodeFlowPKCEManager(
        clientId: "Your Client Id"
    )
)

Before each authentication request your app should generate a code verifier and a code challenge. The code verifier is a cryptographically random string between 43 and 128 characters in length. It can contain letters, digits, underscores, periods, hyphens, and tildes.

In order to generate the code challenge, your app should hash the code verifier using the SHA256 algorithm. Then, base64url encode the hash that you generated. Do not include any = padding characters (percent-encoded or not).

You can use String.randomURLSafe(length:using:) or String.randomURLSafe(length:) to generate the code verifier. You can use the String.makeCodeChallenge(codeVerifier:) instance method to create the code challenge from the code verifier.

For example:

let codeVerifier = String.randomURLSafe(length: 128)
let codeChallenge = String.makeCodeChallenge(codeVerifier: codeVerifier)

// optional, but strongly recommended
let state = String.randomURLSafe(length: 128)

If you use your own method to create these values, you can validate them using this PKCE generator tool. See also Data.base64URLEncodedString() and String.urlSafeCharacters.

Next, create the authorization URL that will be opened in a browser (or web view). When opened, it displays a permissions dialog to the user. The user can then choose to either authorize or deny authorization for your application.

let authorizationURL = spotify.authorizationManager.makeAuthorizationURL(
    redirectURI: URL(string: "Your Redirect URI")!,
    codeChallenge: codeChallenge,
    state: state,
    scopes: [
        .playlistModifyPrivate,
        .userModifyPlaybackState,
        .playlistReadCollaborative,
        .userReadPlaybackPosition
    ]
)!

See the full documentation for makeAuthorizationURL(redirectURI:showDialog:codeChallenge:state:scopes:).

The redirect URI needs to have been entered in the Redirect URI whitelist that you specified when you registered your application using the Spotify Developer Dashboard. DO NOT add a forward-slash to the end of the redirect URI.

The documentation for each endpoint lists the authorization scopes that are required. You can always authorize your application again for different scopes, if necessary. However, this is not an additive process. You must specify all the scopes that you need each time you create the authorization URL.

You can decide how to open the URL. If you are creating an iOS app, the simplest method is to use UIApplication.shared.open(authorizationURL) to open the URL in the browser.

After the user either approves or denies authorization for your app, Spotify will redirect to the redirect URI that you specified when making the authorization URL with query parameters appended to it. Pass this URL into requestAccessAndRefreshTokens(redirectURIWithQuery:codeVerifier:state:) to request the access and refresh tokens:

spotify.authorizationManager.requestAccessAndRefreshTokens(
    redirectURIWithQuery: url,
    // Must match the code verifier that was used to generate the 
    // code challenge when creating the authorization URL.
    codeVerifier: codeVerifier,
    // Must match the value used when creating the authorization URL.
    state: state
)
.sink(receiveCompletion: { completion in
    switch completion {
        case .finished:
            print("successfully authorized")
        case .failure(let error):
            if let authError = error as? SpotifyAuthorizationError, authError.accessWasDenied {
                print("The user denied the authorization request")
            }
            else {
                print("couldn't authorize application: \(error)")
            }
    }
})
.store(in: &cancellables)

Once this publisher completes successfully, your application is authorized and you may begin making requests to the Spotify web API. Ensure that you generate a new value for the state parameter, code verifier, and code challenge before making another authorization request. The access token will be refreshed automatically when necessary. For example:

import SpotifyExampleContent

let playbackRequest = PlaybackRequest(
    context: .uris(
        URIs.Tracks.array(.faces, .illWind, .fearless)
    ),
    offset: .uri(URIs.Tracks.fearless),
    positionMS: 50_000
)

spotify.play(playbackRequest)
    .sink(receiveCompletion: { completion in
        print(completion)
    })
    .store(in: &cancellables)

The full documentation for all of the endpoints can be found here. You are also encouraged to read the Spotify web API reference.

Authorizing with the Authorization Code Flow

Create an instance of SpotifyAPI and assign an instance of AuthorizationCodeFlowManager to the authorizationManager property:

import SpotifyWebAPI

let spotify = SpotifyAPI(
    authorizationManager: AuthorizationCodeFlowManager(
        clientId: "Your Client Id", clientSecret: "Your Client Secret"
    )
)

Next, create the authorization URL that will be opened in a browser (or web view). When opened, it displays a permissions dialog to the user. The user can then choose to either authorize or deny authorization for your application.

let authorizationURL = spotify.authorizationManager.makeAuthorizationURL(
    redirectURI: URL(string: "Your Redirect URI")!,
    showDialog: false,
    scopes: [
        .playlistModifyPrivate,
        .userModifyPlaybackState,
        .playlistReadCollaborative,
        .userReadPlaybackPosition
    ]
)!

See the full documentation for makeAuthorizationURL(redirectURI:showDialog:state:scopes:).

The redirect URI needs to have been entered in the Redirect URI whitelist that you specified when you registered your application using the Spotify Developer Dashboard. DO NOT add a forward-slash to the end of the redirect URI.

The documentation for each endpoint lists the authorization scopes that are required. You can always authorize your application again for different scopes, if necessary. However, this is not an additive process. You must specify all the scopes that you need each time you create the authorization URL.

You can decide how to open the URL. If you are creating an iOS app, the simplest method is to use UIApplication.shared.open(authorizationURL) to open the URL in the browser.

After the user either approves or denies authorization for your app, Spotify will redirect to the redirect URI that you specified when making the authorization URL with query parameters appended to it. Pass this url into requestAccessAndRefreshTokens(redirectURIWithQuery:state:) to request the access and refresh tokens:

spotify.authorizationManager.requestAccessAndRefreshTokens(
    redirectURIWithQuery: url
)
.sink(receiveCompletion: { completion in
    switch completion {
        case .finished:
            print("successfully authorized")
        case .failure(let error):
            if let authError = error as? SpotifyAuthorizationError, authError.accessWasDenied {
                print("The user denied the authorization request")
            }
            else {
                print("couldn't authorize application: \(error)")
            }
    }
})
.store(in: &cancellables)

Once this publisher completes successfully, your application is authorized and you may begin making requests to the Spotify web API. Ensure that you generate a new value for the state parameter before making another authorization request. The access token will be refreshed automatically when necessary. For example:

spotify.currentUserPlaylists()
    .extendPages(spotify)
    .sink(
        receiveCompletion: { completion in
            print(completion)
        },
        receiveValue: { results in
            print(results)
        }
    )
    .store(in: &cancellables)

This authorization process is fully implemented in this example app. The full documentation for all of the endpoints can be found here. You are also encouraged to read the Spotify web API reference.

Authorizing with the Client Credentials Flow

Create an instance of SpotifyAPI and assign an instance of ClientCredentialsFlowManager to the authorizationManager property:

import SpotifyWebAPI

let spotify = SpotifyAPI(
    authorizationManager: ClientCredentialsFlowManager(
        clientId: "Your Client Id", clientSecret: "Your Client Secret"
    )
)

To authorize your application, call authorize():

spotify.authorizationManager.authorize()
    .sink(receiveCompletion: { completion in
        switch completion {
            case .finished:
                print("successfully authorized application")
            case .failure(let error):
                print("could not authorize application: \(error)")
        }
    })
    .store(in: &cancellables)

See the full documentation for authorize.

Once this publisher completes successfully, your application is authorized and you may begin making requests to the Spotify web API. The access token will be refreshed automatically when necessary. For example:

spotify.search(query: "Pink Floyd", categories: [.track])
    .sink(
        receiveCompletion: { completion in
            print(completion)
        },
        receiveValue: { results in
            print(results)
        }
    )
    .store(in: &cancellables)

This authorization process is implemented in this example command-line app. The full documentation for all of the endpoints can be found here. You are also encouraged to read the Spotify web API reference.