Getting Started
Authorization#
There are 3 ways to authenticate with the Spotify Web API:
| Flow | Access User Resources | Requires Secret Key (Server-Side) |
|---|---|---|
| Client Credentials | No | Yes |
| Authorization Code | Yes | Yes |
| Authorization Code with PKCE | Yes | No |
In the following examples, replace "CLIENT_ID" and "CLIENT_SECRET" with your Spotify Application's client ID and secret.
Client Credentials#
ClientCredentialsFlow provides access to all non-user resources.
import asyncio
import spotify
async def main():
auth = await spotify.ClientCredentialsFlow.build_from_access_token(
"CLIENT_ID",
"CLIENT_SECRET",
)
api = spotify.API(auth)
artist = await api.get_artist("0e86yPdC41PGRkLp2Q1Bph")
print(artist.name)
asyncio.run(main())
For the following two authorization code examples:
- quart must be installed
- In the example redirect URI
"https://example.com/account"replaceexample.comwith your own domain. For developing locally,http://localhostis a valid redirect domain. - The redirect URI must be added to your Spotify Application
Authorization Code#
AuthorizationCodeFlow provides access to all resources (including user resources), and should be used when it is safe to store the client's secret key.
import random
import secrets
from quart import Quart, redirect, request, session
import spotify
from spotify import Scope
app = Quart(__name__)
app.secret_key = "SECRET_KEY"
def generate_state() -> str:
possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-~"
state = [secrets.choice(possible) for _ in range(random.randint(43, 128))]
return "".join(state)
@app.get("/")
async def index():
return redirect("/login")
@app.get("/login")
async def login():
session["state"] = generate_state()
url = spotify.AuthorizationCodeFlow.build_url(
client_id="CLIENT_ID",
redirect_uri="https://example.com/account",
state=session["state"],
scopes=[Scope.USER_TOP_READ],
)
return redirect(url)
@app.get("/account")
async def account():
state = request.args.get("state")
error = request.args.get("error")
code = request.args.get("code")
if session.get("state") is None or state != session["state"] or error or not code:
return redirect("/")
session.pop("state")
auth = await spotify.AuthorizationCodeFlow.build_from_access_token(
code,
"https://example.com/account",
client_id="CLIENT_ID",
client_secret="CLIENT_SECRET",
)
api = spotify.API(auth)
top = await api.get_users_top_items(type=spotify.TopItemType.TRACKS)
await api.session.close()
return (
"<ol>"
+ "\n".join(f"<li>{track.name} - {track.artists[0].name}</li>" for track in top.items)
+ "</ol>"
)
app.run()
Authorization Code with PKCE#
AuthorizationCodeFlow (with PKCE) provides access to all resources (including user resources), and should be used when it is not safe to store the client's secret key.
import base64
import hashlib
import random
import secrets
from quart import Quart, redirect, request, session
import spotify
from spotify import Scope
app = Quart(__name__)
app.secret_key = "SECRET_KEY"
def generate_code() -> str:
possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-~"
code = [secrets.choice(possible) for _ in range(random.randint(43, 128))]
return "".join(code)
def safe_sha256(text: str) -> str:
_text = hashlib.sha256(text.encode("ascii"), usedforsecurity=True).digest()
_text = base64.urlsafe_b64encode(_text).decode("ascii")
_text = _text.replace("=", "").replace("+", "-").replace("/", "_")
return _text
@app.get("/")
async def index():
return redirect("/login")
@app.get("/login")
async def login():
session["state"] = generate_code()
session["verifier"] = generate_code()
challenge = safe_sha256(session["verifier"])
url = spotify.AuthorizationCodeFlow.build_url(
client_id="CLIENT_ID",
redirect_uri="https://example.com/account",
state=session["state"],
scopes=[Scope.USER_TOP_READ],
code_challenge=challenge,
)
return redirect(url)
@app.get("/account")
async def account():
state = request.args.get("state")
error = request.args.get("error")
code = request.args.get("code")
if (
session.get("state") is None
or state != session["state"]
or error
or not code
or not session.get("verifier")
):
return redirect("/")
session.pop("state")
verifier = session.pop("verifier")
auth = await spotify.AuthorizationCodeFlow.build_from_access_token(
code,
"https://example.com/account",
client_id="CLIENT_ID",
code_verifier=verifier,
)
api = spotify.API(auth)
top = await api.get_users_top_items(type=spotify.TopItemType.TRACKS)
await api.session.close()
return (
"<ol>"
+ "\n".join(f"<li>{track.name} - {track.artists[0].name}</li>" for track in top.items)
+ "</ol>"
)
app.run()