Skip to content

Commit

Permalink
Fix UserAccessToken fields being private (#103)
Browse files Browse the repository at this point in the history
Closes #101
  • Loading branch information
RAnders00 authored Feb 11, 2021
1 parent 7f79b28 commit def9b62
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Version numbers follow [Semantic Versioning](https://semver.org/).

## Unversioned

- Bugfix: Fixed fields on `UserAccessToken` being all private, preventing library users from constructing the type (as part of the `RefreshingLoginCredentials` system). (#101, #103)
- Reduce the amount of dependencies used. (#96)
- Update `metrics` dependency to v0.14. Metrics are now registered with a description when the
client is created. (#97)
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ async-stream = { version = "0.3.0", optional = true }
maplit = "1.0.2"
env_logger = "0.8.2"
tokio = { version = "1.0", features = ["rt-multi-thread"] }
serde_json = "1.0"

[lib]
name = "twitch_irc"
Expand Down
16 changes: 14 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@
//! use async_trait::async_trait;
//! use twitch_irc::login::{RefreshingLoginCredentials, TokenStorage, UserAccessToken};
//! use twitch_irc::ClientConfig;
//! use std::path::Path;
//!
//! #[derive(Debug)]
//! struct CustomTokenStorage {
Expand All @@ -146,7 +145,12 @@
//!
//! async fn load_token(&mut self) -> Result<UserAccessToken, Self::LoadError> {
//! // Load the currently stored token from the storage.
//! todo!()
//! Ok(UserAccessToken {
//! access_token: todo!(),
//! refresh_token: todo!(),
//! created_at: todo!(),
//! expires_at: todo!()
//! })
//! }
//!
//! async fn update_token(&mut self, token: &UserAccessToken) -> Result<(), Self::UpdateError> {
Expand All @@ -173,6 +177,14 @@
//! on your application, to retrieve the token or update it. For example, you might put the token
//! in a config file you overwrite, some extra file for secrets, or a database.
//!
//! In addition to the structs/traits described above, the login module contains
//! [`GetAccessTokenResponse`](crate::login::GetAccessTokenResponse) as a helper in case you
//! implement the OAuth login process in your application and need to decode the response
//! to `POST /oauth2/token` as part of the
//! [OAuth authorization code flow](https://dev.twitch.tv/docs/authentication/getting-tokens-oauth#oauth-authorization-code-flow).
//! See the documentation on that type for details on usage and how to convert the decoded response
//! to a `UserAccessToken`.
//!
//! # Close the client
//!
//! To close the client, drop all clones of the `TwitchIRCClient` handle. The client will shut down
Expand Down
45 changes: 34 additions & 11 deletions src/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,34 @@ impl LoginCredentials for StaticLoginCredentials {
#[cfg(feature = "refreshing-token")]
#[derive(Debug, Serialize, Deserialize)]
pub struct UserAccessToken {
access_token: String,
refresh_token: String,
created_at: DateTime<Utc>,
expires_at: Option<DateTime<Utc>>,
/// OAuth access token
pub access_token: String,
/// OAuth refresh token
pub refresh_token: String,
/// Timestamp of when this user access token was created
pub created_at: DateTime<Utc>,
/// Timestamp of when this user access token expires. `None` if this token never expires.
pub expires_at: Option<DateTime<Utc>>,
}

/// Represents the Twitch API response to `POST /oauth2/token` API requests.
///
/// Provided as a convenience for your own implementations, as you will typically need
/// to parse this response during the process of getting the inital token after user authorization
/// has been granted.
///
/// Includes a `impl From<GetAccessTokenResponse> for UserAccessToken` for simple
/// conversion to a `UserAccessToken`:
///
/// ```
/// # use twitch_irc::login::{GetAccessTokenResponse, UserAccessToken};
/// let json_response = r#"{"access_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxx","expires_in":14346,"refresh_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","scope":["user_read"],"token_type":"bearer"}"#;
/// let decoded_response: GetAccessTokenResponse = serde_json::from_str(json_response).unwrap();
/// let user_access_token: UserAccessToken = UserAccessToken::from(decoded_response);
/// ```
#[cfg(feature = "refreshing-token")]
#[derive(Deserialize)]
struct RefreshAccessTokenResponse {
pub struct GetAccessTokenResponse {
// {
// "access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
// "expires_in": 14346, // this is entirely OMITTED for infinitely-lived tokens
Expand All @@ -87,14 +106,18 @@ struct RefreshAccessTokenResponse {
// ], // scope is also entirely omitted if we didn't request any scopes in the request
// "token_type": "bearer"
// }
access_token: String,
refresh_token: String,
expires_in: Option<u64>,
/// OAuth access token
pub access_token: String,
/// OAuth refresh token
pub refresh_token: String,
/// Specifies the time when this token expires (number of seconds from now). `None` if this token
/// never expires.
pub expires_in: Option<u64>,
}

#[cfg(feature = "refreshing-token")]
impl From<RefreshAccessTokenResponse> for UserAccessToken {
fn from(response: RefreshAccessTokenResponse) -> Self {
impl From<GetAccessTokenResponse> for UserAccessToken {
fn from(response: GetAccessTokenResponse) -> Self {
let now = Utc::now();
UserAccessToken {
access_token: response.access_token,
Expand Down Expand Up @@ -210,7 +233,7 @@ impl<S: TokenStorage> LoginCredentials for RefreshingLoginCredentials<S> {
.send()
.await
.map_err(RefreshingLoginError::RefreshError)?
.json::<RefreshAccessTokenResponse>()
.json::<GetAccessTokenResponse>()
.await
.map_err(RefreshingLoginError::RefreshError)?;

Expand Down

0 comments on commit def9b62

Please sign in to comment.