Skip to content

Commit cae9804

Browse files
authored
Merge pull request #168 from sby1ce/main
Return access and refresh tokens with `RetrieveTokenError`
2 parents 95aee71 + 2086e96 commit cae9804

File tree

7 files changed

+207
-59
lines changed

7 files changed

+207
-59
lines changed

Cargo.lock

Lines changed: 19 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deny.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ ignore = [
3333
# `instant` is unmaintained
3434
# Dependent on via surf (and http-types)
3535
"RUSTSEC-2024-0384",
36+
# https://rustsec.org/advisories/RUSTSEC-2025-0036
37+
# `surf` is unmaintained
38+
"RUSTSEC-2025-0036",
3639
]
3740

3841
# This section is considered when running `cargo deny check licenses`

examples/device_code_flow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Example of how to create a user token using device code flow.
22
//! The device code flow can be used on confidential and public clients.
3-
use twitch_oauth2::{DeviceUserTokenBuilder, TwitchToken, UserToken};
3+
use twitch_oauth2::{DeviceUserTokenBuilder, TwitchToken};
44

55
#[tokio::main]
66
async fn main() -> anyhow::Result<()> {

src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl Client for SurfClient {
161161
})
162162
.collect::<Result<_, SurfError>>()?;
163163

164-
let _ = std::mem::replace(&mut result.headers_mut(), Some(&mut response_headers));
164+
let _ = result.headers_mut().replace(&mut response_headers);
165165
let result = if let Some(v) = response.version() {
166166
result.version(match v {
167167
surf::http::Version::Http0_9 => http::Version::HTTP_09,

src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ impl AccessTokenRef {
189189
///
190190
/// Should be checked on regularly, according to <https://dev.twitch.tv/docs/authentication/validate-tokens/>
191191
#[cfg(feature = "client")]
192-
pub async fn validate_token<'a, C>(
192+
pub async fn validate_token<C>(
193193
&self,
194-
client: &'a C,
194+
client: &C,
195195
) -> Result<ValidatedToken, ValidationError<<C as Client>::Error>>
196196
where
197197
C: Client,
@@ -226,9 +226,9 @@ impl AccessTokenRef {
226226
///
227227
/// See <https://dev.twitch.tv/docs/authentication/revoke-tokens/>
228228
#[cfg(feature = "client")]
229-
pub async fn revoke_token<'a, C>(
229+
pub async fn revoke_token<C>(
230230
&self,
231-
http_client: &'a C,
231+
http_client: &C,
232232
client_id: &ClientId,
233233
) -> Result<(), RevokeTokenError<<C as Client>::Error>>
234234
where
@@ -287,9 +287,9 @@ impl RefreshTokenRef {
287287
///
288288
/// See <https://dev.twitch.tv/docs/authentication/refresh-tokens>
289289
#[cfg(feature = "client")]
290-
pub async fn refresh_token<'a, C>(
290+
pub async fn refresh_token<C>(
291291
&self,
292-
http_client: &'a C,
292+
http_client: &C,
293293
client_id: &ClientId,
294294
client_secret: Option<&ClientSecret>,
295295
) -> Result<

src/tokens/errors.rs

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Errors
22
3+
use crate::{AccessToken, RefreshToken};
4+
35
/// General errors for talking with twitch, used in [`AppAccessToken::get_app_access_token`](crate::tokens::AppAccessToken::get_app_access_token)
46
#[allow(missing_docs)]
57
#[derive(thiserror::Error, Debug, displaydoc::Display)]
@@ -12,7 +14,7 @@ pub enum AppAccessTokenError<RE: std::error::Error + Send + Sync + 'static> {
1214
RequestParseError(#[from] crate::RequestParseError),
1315
}
1416

15-
/// Errors for [AccessToken::validate_token][crate::AccessTokenRef::validate_token] and [UserToken::from_response][crate::tokens::UserToken::from_response]
17+
/// Errors for [AccessToken::validate_token][crate::AccessTokenRef::validate_token]
1618
#[derive(thiserror::Error, Debug, displaydoc::Display)]
1719
#[non_exhaustive]
1820
pub enum ValidationError<RE: std::error::Error + Send + Sync + 'static> {
@@ -38,15 +40,91 @@ impl ValidationError<std::convert::Infallible> {
3840
}
3941
}
4042

43+
/// Errors for [`UserToken::new`][crate::tokens::UserToken::new], [`UserToken::from_token`][crate::tokens::UserToken::from_token], [`UserToken::from_existing`][crate::tokens::UserToken::from_existing] and [`UserToken::from_response`][crate::tokens::UserToken::from_response]
44+
#[derive(thiserror::Error, Debug)]
45+
#[error("creation of token failed")]
46+
pub struct CreationError<RE: std::error::Error + Send + Sync + 'static> {
47+
/// Access token passed to the function
48+
pub access_token: AccessToken,
49+
/// Refresh token passed to the function
50+
pub refresh_token: Option<RefreshToken>,
51+
/// Error validating the token
52+
#[source]
53+
pub error: ValidationError<RE>,
54+
}
55+
56+
impl<RE: std::error::Error + Send + Sync + 'static>
57+
From<(AccessToken, Option<RefreshToken>, ValidationError<RE>)> for CreationError<RE>
58+
{
59+
fn from(
60+
(access_token, refresh_token, error): (
61+
AccessToken,
62+
Option<RefreshToken>,
63+
ValidationError<RE>,
64+
),
65+
) -> Self {
66+
Self {
67+
access_token,
68+
refresh_token,
69+
error,
70+
}
71+
}
72+
}
73+
4174
/// Errors for [UserToken::from_refresh_token][crate::UserToken::from_refresh_token] and [UserToken::UserToken::from_existing_or_refresh_token][crate::UserToken::from_existing_or_refresh_token]
4275
#[derive(thiserror::Error, Debug, displaydoc::Display)]
4376
#[non_exhaustive]
4477
#[cfg(feature = "client")]
4578
pub enum RetrieveTokenError<RE: std::error::Error + Send + Sync + 'static> {
4679
/// could not validate token
47-
ValidationError(#[from] ValidationError<RE>),
80+
ValidationError {
81+
/// Error validating the token
82+
#[source]
83+
error: ValidationError<RE>,
84+
/// Access token passed to the function
85+
access_token: AccessToken,
86+
/// Refresh token passed to the function
87+
refresh_token: Option<RefreshToken>,
88+
},
4889
/// could not refresh token
49-
RefreshTokenError(#[from] RefreshTokenError<RE>),
90+
RefreshTokenError {
91+
/// Error refreshing the token
92+
#[source]
93+
error: RefreshTokenError<RE>,
94+
/// Refresh token passed to the function
95+
refresh_token: RefreshToken,
96+
},
97+
}
98+
99+
#[cfg(feature = "client")]
100+
impl<RE: std::error::Error + Send + Sync + 'static> From<CreationError<RE>>
101+
for RetrieveTokenError<RE>
102+
{
103+
fn from(
104+
CreationError {
105+
error,
106+
access_token,
107+
refresh_token,
108+
}: CreationError<RE>,
109+
) -> Self {
110+
RetrieveTokenError::ValidationError {
111+
error,
112+
access_token,
113+
refresh_token,
114+
}
115+
}
116+
}
117+
118+
#[cfg(feature = "client")]
119+
impl CreationError<std::convert::Infallible> {
120+
/// Convert this error from a infallible to another
121+
pub fn into_other<RE: std::error::Error + Send + Sync + 'static>(self) -> CreationError<RE> {
122+
CreationError {
123+
access_token: self.access_token,
124+
refresh_token: self.refresh_token,
125+
error: self.error.into_other(),
126+
}
127+
}
50128
}
51129

52130
/// Errors for [AccessToken::revoke_token][crate::AccessTokenRef::revoke_token]
@@ -96,6 +174,15 @@ pub enum UserTokenExchangeError<RE: std::error::Error + Send + Sync + 'static> {
96174
ValidationError(#[from] ValidationError<RE>),
97175
}
98176

177+
#[cfg(feature = "client")]
178+
impl<RE: std::error::Error + Send + Sync + 'static> From<CreationError<RE>>
179+
for UserTokenExchangeError<RE>
180+
{
181+
fn from(value: CreationError<RE>) -> Self {
182+
UserTokenExchangeError::ValidationError(value.error)
183+
}
184+
}
185+
99186
/// Errors for [ImplicitUserTokenBuilder::get_user_token][crate::tokens::ImplicitUserTokenBuilder::get_user_token]
100187
#[derive(thiserror::Error, Debug, displaydoc::Display)]
101188
#[non_exhaustive]
@@ -114,6 +201,16 @@ pub enum ImplicitUserTokenExchangeError<RE: std::error::Error + Send + Sync + 's
114201
/// could not get validation for token
115202
ValidationError(#[from] ValidationError<RE>),
116203
}
204+
205+
#[cfg(feature = "client")]
206+
impl<RE: std::error::Error + Send + Sync + 'static> From<CreationError<RE>>
207+
for ImplicitUserTokenExchangeError<RE>
208+
{
209+
fn from(value: CreationError<RE>) -> Self {
210+
ImplicitUserTokenExchangeError::ValidationError(value.error)
211+
}
212+
}
213+
117214
/// Errors for [`DeviceUserTokenBuilder`][crate::tokens::DeviceUserTokenBuilder]
118215
#[derive(thiserror::Error, Debug, displaydoc::Display)]
119216
#[non_exhaustive]
@@ -147,3 +244,12 @@ impl<RE: std::error::Error + Send + Sync + 'static> DeviceUserTokenExchangeError
147244
) if message == "authorization_pending")
148245
}
149246
}
247+
248+
#[cfg(feature = "client")]
249+
impl<RE: std::error::Error + Send + Sync + 'static> From<CreationError<RE>>
250+
for DeviceUserTokenExchangeError<RE>
251+
{
252+
fn from(value: CreationError<RE>) -> Self {
253+
DeviceUserTokenExchangeError::ValidationError(value.error)
254+
}
255+
}

0 commit comments

Comments
 (0)