-
Notifications
You must be signed in to change notification settings - Fork 124
/
Copy pathwith_refresh_token.rs
165 lines (147 loc) · 6.24 KB
/
with_refresh_token.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Refresh tokens aren't meant to expire, so they can be used as a persistent
//! authentication method without the need for user's interaction for oauth
//! requests. You still need to authenticate the usual way at least once to
//! obtain the refresh token, and you may need to obtain a new one if you change
//! the required scopes.
//!
//! The cache generated by `get_token` uses the refresh token under the hood to
//! automatically authenticate the user. This example shows how it's done
//! because sometimes it's not possible to use this cache file (a web server for
//! example).
//!
//! *Note*: refresh tokens can actually expire, [as the OAuth2 spec
//! indicates](https://tools.ietf.org/html/rfc6749#section-6), but this [hasn't
//! actually happened in months with some
//! tokens](https://github.com/felix-hilden/tekore/issues/86), so in the case of
//! Spotify it doesn't seem to revoke them at all.
use rspotify::{
model::ArtistId, prelude::*, scopes, AuthCodePkceSpotify, AuthCodeSpotify, Credentials, OAuth,
};
// Sample request that will follow some artists, print the user's
// followed artists, and then unfollow the artists.
async fn do_things(spotify: &AuthCodeSpotify) {
let artists = [
ArtistId::from_id("3RGLhK1IP9jnYFH4BRFJBS").unwrap(), // The Clash
ArtistId::from_id("0yNLKJebCb8Aueb54LYya3").unwrap(), // New Order
ArtistId::from_id("2jzc5TC5TVFLXQlBNiIUzE").unwrap(), // a-ha
];
let num_artists = artists.len();
spotify
.user_follow_artists(artists.iter().map(|a| a.as_ref()))
.await
.expect("couldn't follow artists");
println!("Followed {num_artists} artists successfully.");
// Printing the followed artists
let followed = spotify
.current_user_followed_artists(None, None)
.await
.expect("couldn't get user followed artists");
println!(
"User currently follows at least {} artists.",
followed.items.len()
);
spotify
.user_unfollow_artists(artists)
.await
.expect("couldn't unfollow artists");
println!("Unfollowed {num_artists} artists successfully.");
}
// Sample request that will follow some artists, print the user's
// followed artists, and then unfollow the artists.
async fn pkce_do_things(spotify: &AuthCodePkceSpotify) {
let artists = [
ArtistId::from_id("3RGLhK1IP9jnYFH4BRFJBS").unwrap(), // The Clash
ArtistId::from_id("0yNLKJebCb8Aueb54LYya3").unwrap(), // New Order
ArtistId::from_id("2jzc5TC5TVFLXQlBNiIUzE").unwrap(), // a-ha
];
let num_artists = artists.len();
spotify
.user_follow_artists(artists.iter().map(|a| a.as_ref()))
.await
.expect("AuthCodePkceSpotify couldn't follow artists");
println!("AuthCodePkceSpotify Followed {num_artists} artists successfully.");
// Printing the followed artists
let followed = spotify
.current_user_followed_artists(None, None)
.await
.expect("couldn't get user followed artists");
println!(
"AuthCodePkceSpotify User currently follows at least {} artists.",
followed.items.len()
);
spotify
.user_unfollow_artists(artists)
.await
.expect("couldn't unfollow artists");
println!("AuthCodePkceSpotify Unfollowed {num_artists} artists successfully.");
}
async fn refresh_pkce_code(creds: Credentials, oauth: OAuth) {
let mut spotify = AuthCodePkceSpotify::new(creds.clone(), oauth.clone());
// Obtaining the access token
let url = spotify.get_authorize_url(None).unwrap();
// This function requires the `cli` feature enabled.
spotify.prompt_for_token(&url).await.unwrap();
// Token refreshing works as well, but should with the one generated in the
// previous request
pkce_do_things(&spotify).await;
// At a different time, the refresh token can be used to refresh an access
// token directly and run requests:
println!(">>> Pkce Session two, running some requests:");
// No `prompt_for_user_token` needed.
spotify
.refresh_token()
.await
.expect("couldn't refresh user token");
pkce_do_things(&spotify).await;
// This process can now be repeated multiple times by using only the
// refresh token that was obtained at the beginning.
println!(">>> Pkce Session three, running some requests:");
spotify
.refresh_token()
.await
.expect("couldn't refresh user token");
pkce_do_things(&spotify).await;
}
async fn refresh_auth_code(creds: Credentials, oauth: OAuth) {
let spotify = AuthCodeSpotify::new(creds.clone(), oauth.clone());
// In the first session of the application we authenticate and obtain the
// refresh token. We can also do some requests here.
println!(">>> Session one, obtaining refresh token and running some requests:");
let url = spotify.get_authorize_url(false).unwrap();
// This function requires the `cli` feature enabled.
spotify
.prompt_for_token(&url)
.await
.expect("couldn't authenticate successfully");
// Token refreshing works as well, but should with the one generated in the
// previous request
do_things(&spotify).await;
// At a different time, the refresh token can be used to refresh an access
// token directly and run requests:
println!(">>> Session two, running some requests:");
// No `prompt_for_user_token` needed.
spotify
.refresh_token()
.await
.expect("couldn't refresh user token");
do_things(&spotify).await;
// This process can now be repeated multiple times by using only the
// refresh token that was obtained at the beginning.
println!(">>> Session three, running some requests:");
spotify
.refresh_token()
.await
.expect("couldn't refresh user token");
do_things(&spotify).await;
}
#[tokio::main]
async fn main() {
// You can use any logger for debugging.
env_logger::init();
// May require the `env-file` feature enabled if the environment variables
// aren't configured manually.
let creds = Credentials::from_env().unwrap();
let oauth = OAuth::from_env(scopes!("user-follow-read user-follow-modify")).unwrap();
refresh_auth_code(creds.clone(), oauth.clone()).await;
refresh_pkce_code(creds, oauth).await;
}