twitch_oauth2/tokens/
errors.rs

1//! Errors
2
3use crate::{AccessToken, RefreshToken};
4
5/// General errors for talking with twitch, used in [`AppAccessToken::get_app_access_token`](crate::tokens::AppAccessToken::get_app_access_token)
6#[allow(missing_docs)]
7#[derive(thiserror::Error, Debug, displaydoc::Display)]
8#[cfg(feature = "client")]
9#[non_exhaustive]
10pub enum AppAccessTokenError<RE: std::error::Error + Send + Sync + 'static> {
11    /// request for token failed
12    Request(#[source] RE),
13    /// could not parse response when getting app access token
14    RequestParseError(#[from] crate::RequestParseError),
15}
16
17/// Errors for [AccessToken::validate_token][crate::AccessTokenRef::validate_token]
18#[derive(thiserror::Error, Debug, displaydoc::Display)]
19#[non_exhaustive]
20pub enum ValidationError<RE: std::error::Error + Send + Sync + 'static> {
21    /// token is not authorized for use
22    NotAuthorized,
23    /// could not parse response when validating token
24    RequestParseError(#[from] crate::RequestParseError),
25    /// failed to request validation
26    Request(#[source] RE),
27    /// given token is not of the correct token type: {0}
28    InvalidToken(&'static str),
29}
30
31impl ValidationError<std::convert::Infallible> {
32    /// Convert this error from a infallible to another
33    pub fn into_other<RE: std::error::Error + Send + Sync + 'static>(self) -> ValidationError<RE> {
34        match self {
35            ValidationError::NotAuthorized => ValidationError::NotAuthorized,
36            ValidationError::RequestParseError(e) => ValidationError::RequestParseError(e),
37            ValidationError::InvalidToken(s) => ValidationError::InvalidToken(s),
38            ValidationError::Request(_) => unreachable!(),
39        }
40    }
41}
42
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")]
46pub 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
56impl<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
74/// 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]
75#[derive(thiserror::Error, Debug, displaydoc::Display)]
76#[non_exhaustive]
77#[cfg(feature = "client")]
78pub enum RetrieveTokenError<RE: std::error::Error + Send + Sync + 'static> {
79    /// could not validate token
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    },
89    /// could not refresh token
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")]
100impl<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")]
119impl 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    }
128}
129
130/// Errors for [AccessToken::revoke_token][crate::AccessTokenRef::revoke_token]
131#[allow(missing_docs)]
132#[derive(thiserror::Error, Debug, displaydoc::Display)]
133#[non_exhaustive]
134#[cfg(feature = "client")]
135pub enum RevokeTokenError<RE: std::error::Error + Send + Sync + 'static> {
136    /// could not parse response when revoking token
137    RequestParseError(#[from] crate::RequestParseError),
138    /// failed to do revokation
139    RequestError(#[source] RE),
140}
141
142/// Errors for [TwitchToken::refresh_token][crate::TwitchToken::refresh_token]
143#[allow(missing_docs)]
144#[derive(thiserror::Error, Debug, displaydoc::Display)]
145#[non_exhaustive]
146#[cfg(feature = "client")]
147pub enum RefreshTokenError<RE: std::error::Error + Send + Sync + 'static> {
148    /// request when refreshing token failed
149    RequestError(#[source] RE),
150    /// could not parse response when refreshing token.
151    RequestParseError(#[from] crate::RequestParseError),
152    /// no client secret found
153    // TODO: Include this in doc
154    // A client secret is needed to request a refreshed token.
155    NoClientSecretFound,
156    /// no refresh token found
157    NoRefreshToken,
158    /// no expiration found on new token
159    NoExpiration,
160}
161
162/// Errors for [`UserTokenBuilder::get_user_token`](crate::tokens::UserTokenBuilder::get_user_token) and [`UserToken::mock_token`](crate::tokens::UserToken::mock_token)
163#[derive(thiserror::Error, Debug, displaydoc::Display)]
164#[non_exhaustive]
165#[cfg(feature = "client")]
166pub enum UserTokenExchangeError<RE: std::error::Error + Send + Sync + 'static> {
167    /// request for user token failed
168    RequestError(#[source] RE),
169    /// could not parse response when getting user token
170    RequestParseError(#[from] crate::RequestParseError),
171    /// state CSRF does not match when exchanging user token
172    StateMismatch,
173    /// could not get validation for user token
174    ValidationError(#[from] ValidationError<RE>),
175}
176
177#[cfg(feature = "client")]
178impl<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
186/// Errors for [ImplicitUserTokenBuilder::get_user_token][crate::tokens::ImplicitUserTokenBuilder::get_user_token]
187#[derive(thiserror::Error, Debug, displaydoc::Display)]
188#[non_exhaustive]
189#[cfg(feature = "client")]
190pub enum ImplicitUserTokenExchangeError<RE: std::error::Error + Send + Sync + 'static> {
191    // FIXME: should be TwitchTokenErrorResponse
192    /// twitch returned an error: {error:?} - {description:?}
193    TwitchError {
194        /// Error type
195        error: Option<String>,
196        /// Description of error
197        description: Option<String>,
198    },
199    /// state CSRF does not match
200    StateMismatch,
201    /// could not get validation for token
202    ValidationError(#[from] ValidationError<RE>),
203}
204
205#[cfg(feature = "client")]
206impl<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
214/// Errors for [`DeviceUserTokenBuilder`][crate::tokens::DeviceUserTokenBuilder]
215#[derive(thiserror::Error, Debug, displaydoc::Display)]
216#[non_exhaustive]
217#[cfg(feature = "client")]
218pub enum DeviceUserTokenExchangeError<RE: std::error::Error + Send + Sync + 'static> {
219    /// request for exchange token failed
220    DeviceExchangeRequestError(#[source] RE),
221    /// could not parse response when getting exchange token
222    DeviceExchangeParseError(#[source] crate::RequestParseError),
223    /// request for user token failed
224    TokenRequestError(#[source] RE),
225    /// could not parse response when getting user token
226    TokenParseError(#[source] crate::RequestParseError),
227    /// could not get validation for token
228    ValidationError(#[from] ValidationError<RE>),
229    /// no device code found, exchange not started
230    NoDeviceCode,
231    /// the device code has expired
232    Expired,
233}
234
235#[cfg(feature = "client")]
236impl<RE: std::error::Error + Send + Sync + 'static> DeviceUserTokenExchangeError<RE> {
237    /// Check if the error is due to the authorization request being pending
238    pub fn is_pending(&self) -> bool {
239        matches!(self, DeviceUserTokenExchangeError::TokenParseError(
240                crate::RequestParseError::TwitchError(crate::id::TwitchTokenErrorResponse {
241                    message,
242                    ..
243                }),
244            ) if message == "authorization_pending")
245    }
246}
247
248#[cfg(feature = "client")]
249impl<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}