You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -54,20 +54,25 @@ If you have a question, you can:
54
54
3. Contact me using **Adam#9261** on [Discord](https://discordapp.com)
55
55
56
56
## Creating a new api instance
57
-
To decide which api you need (SpotifyAppApi, SpotifyClientApi, SpotifyImplicitGrantApi), please refer to
58
-
https://developer.spotify.com/documentation/general/guides/authorization-guide/. In general:
57
+
To decide which api you need (SpotifyAppApi, SpotifyClientApi, SpotifyImplicitGrantApi), you can refer
58
+
to the sections below or the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/). In general:
59
59
- If you don't need client resources, use SpotifyAppApi
60
60
- If you're using the api in a backend application, use SpotifyClientApi (with or without PKCE)
61
61
- If you're using the api in Kotlin/JS browser, use SpotifyImplicitGrantApi
62
-
- If you need access to client resources in an Android or other application, use SpotifyClientApi with PKCe
62
+
- If you need access to client resources in an Android or other application, use SpotifyClientApi with PKCE
63
63
64
64
65
65
### SpotifyAppApi
66
-
This provides access only to public Spotify endpoints. By default, the SpotifyApi `Token` automatically regenerates when needed. This can be changed
67
-
through the `automaticRefresh` parameter in all builders.
66
+
This provides access only to public Spotify endpoints.
67
+
Use this when you have a server-side application. Note that implicit grant authorization
68
+
provides a higher api ratelimit, so consider using implicit grant if your application has
69
+
significant usage.
70
+
71
+
By default, the SpotifyApi `Token` automatically regenerates when needed.
72
+
This can be changed by overriding the `automaticRefresh` builder setting.
68
73
69
74
There are four exposed builders, depending on the level of control you need over api creation.
70
-
Please see the [spotifyAppApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-app-api.html) for a full list of available builders.
75
+
Please see the [spotifyAppApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-app-api.html) for a full list of available builders.
71
76
72
77
You will need:
73
78
- Spotify application client id
@@ -80,24 +85,189 @@ val api = spotifyAppApi("clientId", "clientSecret").build() // create and build
80
85
println(api.browse.getNewReleases().complete()) // use it
81
86
```
82
87
83
-
Example creation, using an existing Token
84
-
88
+
Example creation, using an existing Token and setting automatic token refresh to false
89
+
```kotlin
90
+
val token = spotifyAppApi(spotifyClientId, spotifyClientSecret).build().token
91
+
val api = spotifyAppApi(
92
+
"clientId",
93
+
"clientSecret",
94
+
token,
95
+
SpotifyApiOptionsBuilder(
96
+
automaticRefresh =false
97
+
)
98
+
)
99
+
println(api.browse.getNewReleases().complete()) // use it
100
+
```
85
101
86
102
### SpotifyClientApi
87
-
The `SpotifyClientApi` is a superset of `SpotifyApi`; thus, you have access to all `SpotifyApi` methods in `SpotifyClientApi`.
88
-
This library does not provide a method to retrieve the code from your callback url; you must implement that with a web server.
103
+
The `SpotifyClientApi` is a superset of `SpotifyApi`; thus, nothing changes if you want to
104
+
access public data.
105
+
This library does not provide a method to retrieve the code from your callback url; instead,
106
+
you must implement that with a web server.
107
+
Automatic refresh is available *only* when building with an authorization code or a
108
+
`Token` object. Otherwise, it will expire `Token.expiresIn` seconds after creation.
89
109
90
110
Make sure your application has requested the proper [Scopes](https://developer.spotify.com/web-api/using-spotifyScopes/) in order to
91
-
ensure proper function of this library.
111
+
ensure proper function of this library. The api option `requiredScopes` allows you to verify
112
+
that a client has actually authorized with the scopes you are expecting.
92
113
93
-
Its automatic refresh ability is available *only* when building with
94
-
an authorization code or a `Token` object. Otherwise, it will expire `Token.expiresIn` seconds after creation.
114
+
You will need:
115
+
- Spotify application client id
116
+
- Spotify application client secret (if not using PKCE)
117
+
- Spotify application redirect uri
118
+
- To choose which client authorization method (PKCE or non-PKCE) to use
119
+
120
+
#### PKCE
121
+
Use the PKCE builders and helper methods if you are using the Spotify client authorization PKCE flow.
122
+
Building via PKCE returns a `SpotifyClientApi` which has modified refresh logic.
123
+
124
+
Use cases:
125
+
1. You are using this library in an application (likely Android), or do not want to expose the client secret.
126
+
127
+
To learn more about the PKCE flow, please read the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow).
128
+
Some highlights about the flow are:
129
+
- It is refreshable, but each refresh token can only be used once. This library handles token refresh automatically by default
130
+
- It does not require a client secret; instead, a set redirect uri and a random code verifier
131
+
are used to verify the authenticity of the authorization.
132
+
- A code verifier is required. The code verifier is "*a cryptographically random string between 43 and 128 characters in length.
133
+
It can contain letters, digits, underscores, periods, hyphens, or tildes.*"
134
+
- A code challenge is required. "*In order to generate the code challenge, your app should
135
+
hash the code verifier using the SHA256 algorithm. Then, base64url encode the hash that you generated.*"
136
+
- When creating a pkce api instance, the code verifier is passed in by you and compared to
137
+
the code challenge used to authorize the user.
138
+
139
+
This library contains helpful methods that can be used to simplify the PKCE authorization process.
140
+
This includes `getSpotifyPkceCodeChallenge` (not available in the Kotlin/JS target), which SHA256 hashes and base64url encodes the code
141
+
challenge, and `getPkceAuthorizationUrl`, which allows you to generate an easy authorization url for PKCE flow.
142
+
143
+
Please see the [spotifyClientPkceApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-pkce-api.html) for a full list of available builders.
144
+
145
+
**Takeaway**: Use PKCE authorization flow in applications where you cannot secure the client secret.
146
+
147
+
To get a PKCE authorization url, to which you can redirect a user, you can use the `getPkceAuthorizationUrl`
148
+
top-level method. An example is shown below, requesting 4 different scopes.
149
+
```kotlin
150
+
val codeVerifier ="thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
151
+
val codeChallenge = getSpotifyPkceCodeChallenge(codeVerifier) // helper method
152
+
val url:String= getPkceAuthorizationUrl(
153
+
SpotifyScope.PLAYLIST_READ_PRIVATE,
154
+
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
155
+
SpotifyScope.USER_FOLLOW_READ,
156
+
SpotifyScope.USER_LIBRARY_MODIFY,
157
+
clientId ="clientId",
158
+
redirectUri ="your-redirect-uri",
159
+
codeChallenge = codeChallenge
160
+
)
161
+
```
162
+
163
+
There is also an optional parameter `state`, which helps you verify the authorization.
164
+
165
+
**Note**: If you want automatic token refresh, you need to pass in your application client id and redirect uri
166
+
when using the `spotifyClientPkceApi`.
167
+
168
+
##### Example: A user has authorized your application. You now have the authorization code obtained after the user was redirected back to your application. You want to create a new `SpotifyClientApi`.
169
+
```kotlin
170
+
val codeVerifier ="thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
171
+
val code:String=...
172
+
val api = spotifyClientPkceApi(
173
+
"clientId", // optional. include for token refresh
174
+
"your-redirect-uri", // optional. include for token refresh
175
+
code,
176
+
codeVerifier, // the same code verifier you used to generate the code challenge
To get a non-PKCE authorization url, to which you can redirect a user, you can use the `getSpotifyAuthorizationUrl`
186
+
top-level method. An example is shown below, requesting 4 different scopes.
187
+
```kotlin
188
+
val url:String= getSpotifyAuthorizationUrl(
189
+
SpotifyScope.PLAYLIST_READ_PRIVATE,
190
+
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
191
+
SpotifyScope.USER_FOLLOW_READ,
192
+
SpotifyScope.USER_LIBRARY_MODIFY,
193
+
clientId ="clientId",
194
+
redirectUri ="your-redirect-uri",
195
+
state ="your-special-state"// optional
196
+
)
197
+
```
198
+
There are also several optional parameters, allowing you to set whether the authorization url is meant
199
+
for implicit grant flow, the state, and whether a re-authorization dialog should be shown to users.
200
+
201
+
There are several exposed builders, depending on the level of control you need over api creation.
202
+
Please see the [spotifyClientApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-api.html) for a full list of available builders.
203
+
204
+
##### Example: You've redirected the user back to your web server and have an authorization code (code).
205
+
In this example, automatic token refresh is turned on by default.
206
+
```kotlin
207
+
val authCode =""
208
+
val api = spotifyClientApi(
209
+
"clientId",
210
+
"clientSecret",
211
+
"your-redirect-uri",
212
+
authCode
213
+
).build() // create and build api
214
+
println(api.personalization.getTopTracks(limit =5).complete().items.map { it.name }) // print user top tracks
215
+
```
216
+
217
+
##### Example: You've saved a user's token from previous authorization and need to create an api instance.
218
+
In this case, if you provide a client id to the builder, automatic token refresh will also be turned on.
219
+
```kotlin
220
+
val token:Token=... // your existing token
221
+
val api = spotifyClientApi(
222
+
"clientId",
223
+
"clientSecret",
224
+
"your-redirect-uri",
225
+
token,
226
+
SpotifyApiOptionsBuilder(
227
+
onTokenRefresh = {
228
+
println("Token refreshed at ${System.currentTimeMillis()}")
Please see the [spotifyClientApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-api.html) for a full list of available builders, or the client [samples](https://github.com/adamint/spotify-web-api-kotlin/tree/master/samples/jvm/src/main/kotlin/clientApi).
97
235
98
236
### SpotifyImplicitGrantApi
99
-
Instantiate this api only if you are using the Spotify implicit grant flow. It is a superset of `SpotifyClientApi`.
100
-
Please see the [spotifyImplicitGrantApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-implicit-grant-api.html) for a full list of available builders, or the implicit grant [samples (tbd)]().
237
+
Use the `SpotifyImplicitGrantApi` if you are using the Spotify implicit grant flow.
238
+
`SpotifyImplicitGrantApi` is a superset of `SpotifyClientApi`.
239
+
Unlike the other builders, the `spotifyImplicitGrantApi` builder method directly returns
240
+
a `SpotifyImplicitGrantApi` instead of an api builder.
241
+
242
+
Use cases:
243
+
1. You are using the **Kotlin/JS** target for this library.
244
+
2. Your frontend Javascript passes the token received through the implicit grant flow to your
245
+
backend, where it is then used to create an api instance.
246
+
247
+
To learn more about the implicit grant flow, please read the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow).
248
+
Some highlights about the flow are:
249
+
- It is non-refreshable
250
+
- It is client-side
251
+
- It does not require a client secret
252
+
253
+
Please see the [spotifyImplicitGrantApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-implicit-grant-api.html) for a full list of available builders.
254
+
255
+
The Kotlin/JS target contains the `parseSpotifyCallbackHashToToken` method, which will parse the hash
256
+
for the current url into a Token object, with which you can then instantiate the api.
257
+
258
+
**Takeaway**: There are two ways to use implicit grant flow, browser-side only and browser and
259
+
server. This library provides easy access for both.
260
+
261
+
##### Example
262
+
```kotlin
263
+
val token:Token=...
264
+
val api = spotifyImplicitGrantApi(
265
+
null,
266
+
null,
267
+
token
268
+
) // create api. there is no need to build it
269
+
println(api.personalization.getTopArtists(limit =1).complete()[0].name) // use it
270
+
```
101
271
102
272
### SpotifyApiBuilder Block & setting API options
103
273
There are three pluggable blocks in each api's corresponding builder
@@ -123,6 +293,9 @@ most of the default values either allow for significant performance or feature e
123
293
-`allowBulkRequests`: Allow splitting too-large requests into smaller, allowable api requests. Default: true
124
294
-`requestTimeoutMillis`: The maximum time, in milliseconds, before terminating an http request. Default: 100000ms
125
295
-`refreshTokenProducer`: Provide if you want to use your own logic when refreshing a Spotify token.
296
+
-`requiredScopes`: Scopes that your application requires to function (only applicable to `SpotifyClientApi` and `SpotifyImplicitGrantApi`).
297
+
This verifies that the token your user authorized with actually contains the scopes your
298
+
application needs to function.
126
299
127
300
Notes:
128
301
- Unless you have a good reason otherwise, `useCache` should be true
@@ -131,10 +304,29 @@ Notes:
131
304
-`allowBulkRequests` for example, lets you query 80 artists in one wrapper call by splitting it into 50 artists + 30 artists
132
305
-`refreshTokenProducer` is useful when you want to re-authorize with the Spotify Auth SDK or elsewhere
133
306
134
-
### Tips
135
-
-
136
-
137
-
307
+
### Using the API
308
+
APIs available in all `SpotifyApi` instances, including `SpotifyClientApi` and `SpotifyImplicitGrantApi`:
309
+
-`SearchApi` (searching items)
310
+
-`AlbumApi` (get information about albums)
311
+
-`BrowseApi` (browse new releases, featured playlists, categories, and recommendations)
312
+
-`ArtistApi` (get information about artists)
313
+
-`PlaylistApi` (get information about playlists)
314
+
-`UserApi` (get public information about users on Spotify)
APIs available only in `SpotifyClientApi` and `SpotifyImplicitGrantApi` instances:
319
+
-`ClientSearchApi` (all the methods in `SearchApi`, and searching shows and episodes)
320
+
-`EpisodeApi` (get information about episodes)
321
+
-`ShowApi` (get information about shows)
322
+
-`ClientPlaylistApi` (all the methods in `PlaylistApi`, and get and manage user playlists)
323
+
-`ClientProfileApi` (all the methods in `UserApi`, and get the user profile, depending on scopes)
324
+
-`ClientFollowingApi` (all the methods in `FollowingApi`, and get and manage following of playlists, artists, and users)
325
+
-`ClientPersonalizationApi` (get user top tracks and artists)
326
+
-`ClientLibraryApi` (get and manage saved tracks and albums)
327
+
-`ClientPlayerApi` (view and control Spotify playback)
328
+
329
+
## Tips
138
330
139
331
### Building the API
140
332
The easiest way to build the API is synchronously using .build() after a builder
@@ -143,7 +335,7 @@ The easiest way to build the API is synchronously using .build() after a builder
143
335
spotifyAppApi(clientId, clientSecret).build()
144
336
```
145
337
146
-
You can also build the API asynchronously using kotlin coroutines!
338
+
You can also build the API asynchronously using Kotlin coroutines.
147
339
```kotlin
148
340
runBlocking {
149
341
spotifyAppApi(clientId, clientSecret).buildAsyncAt(this) { api ->
@@ -152,7 +344,7 @@ runBlocking {
152
344
}
153
345
```
154
346
155
-
## What is the SpotifyRestAction class?
347
+
###What is the SpotifyRestAction class?
156
348
Abstracting requests into a `SpotifyRestAction` class allows for a lot of flexibility in sending and receiving requests.
157
349
This class includes options for asynchronous and blocking execution in all endpoints. However,
158
350
due to this, you **must** call one of the provided methods in order for the call
@@ -171,13 +363,12 @@ time, this will likely be accurate within a few milliseconds.
171
363
-`asFuture()` transforms the supplier into a `CompletableFuture` (only JVM)
172
364
173
365
### SpotifyRestPagingAction
174
-
Separate from, but a superset of SpotifyRestAction, this specialized implementation of RestActions is
175
-
just for [AbstractPagingObject] (`PagingObject` and `CursorBasedPagingObject`). This class gives you the same functionality as SpotifyRestAction,
366
+
Separate from, but a superset of SpotifyRestAction, this specialized implementation of RestActions includes extensions
367
+
for `AbstractPagingObject` (`PagingObject` and `CursorBasedPagingObject`). This class gives you the same functionality as SpotifyRestAction,
176
368
but you also have the ability to retrieve *all* of its items or linked PagingObjects, or a *subset* of its items or linked PagingObjects with one call, with
177
369
a single method call to `getAllItems()` or `getAllPagingObjects()`, or `getWithNext(total: Int, context: CoroutineContext = Dispatchers.Default)` or `getWithNextItems(total: Int, context: CoroutineContext = Dispatchers.Default)` respectively
178
370
179
-
180
-
## Using the Library
371
+
## Design Notes
181
372
### The benefits of LinkedResults, PagingObjects, and Cursor-based Paging Objects
182
373
Spotify provides these three object models in order to simplify our lives as developers. So let's see what we
0 commit comments