twitch_oauth2

Struct UserTokenBuilder

Source
pub struct UserTokenBuilder { /* private fields */ }
Expand description

Builder for OAuth authorization code flow

See ImplicitUserTokenBuilder for the OAuth implicit code flow (does not require Client Secret)

§Examples

See also the auth flow example

To generate a user token with this auth flow, you need to:

  1. Initialize the UserTokenBuilder with UserTokenBuilder::new, providing your client id, client secret, and a redirect URL. Use set_scopes(vec![]) to add any necessary scopes to the request. You can also use force_verify(true) to force the user to re-authorize your app’s access to their resources.

    Make sure you’ve added the redirect URL to the app settings on the Twitch Developer Console.

    use twitch_oauth2::{id::TwitchTokenResponse, tokens::UserTokenBuilder, Scope};
    use url::Url;
    
    // This is the URL the user will be redirected to after authorizing your application
    let redirect_url = Url::parse("http://localhost/twitch/register")?;
    let mut builder = UserTokenBuilder::new("myclientid", "myclientsecret", redirect_url);
    builder = builder.set_scopes(vec![Scope::ChatRead, Scope::ChatEdit]);
    builder = builder.force_verify(true); // Defaults to false
  2. Generate a URL for the user to visit using generate_url(). This method also returns a CSRF token that you need to save for later validation.

    let (url, csrf_token) = builder.generate_url();
    // Make your user navigate to this URL, for example
    println!("Visit this URL to authorize Twitch access: {}", url);
  3. Have the user visit the generated URL. They will be asked to authorize your application if they haven’t previously done so or if you’ve set force_verify to true.

    You can do this by providing the link in a web page, have the user be directed, the console, or by opening it in a browser.

    If this is a web server, you should store the UserTokenBuilder somewhere you can retrieve it later. A good place to store it is in a Cache or a HashMap with the CSRF token as the key.

  4. When the user has been redirected to the redirect URL by twitch, extract the state and code query parameters from the URL.

    use std::borrow::Cow;
    use std::collections::BTreeMap;
    
    fn extract_pair<'a>(
        query: &BTreeMap<Cow<'a, str>, Cow<'a, str>>,
        key1: &str,
        key2: &str,
    ) -> Option<(Cow<'a, str>, Cow<'a, str>)> {
        Some((query.get(key1)?.clone(), query.get(key2)?.clone()))
    }
    
    /// Extract the state and code from the URL a user was redirected to after authorizing the application.
    fn extract_url<'a>(
        url: &'a url::Url,
    ) -> Result<(Cow<'a, str>, Cow<'a, str>), Option<(Cow<'a, str>, Cow<'a, str>)>> {
        let query: BTreeMap<_, _> = url.query_pairs().collect();
        if let Some((error, error_description)) = extract_pair(&query, "error", "error_description") {
            Err(Some((error, error_description)))
        } else if let Some((state, code)) = extract_pair(&query, "state", "code") {
            Ok((state, code))
        } else {
            Err(None)
        }
    }
  5. Finally, call get_user_token with the state and code query parameters to get the user’s access token.

    let client = reqwest::Client::builder()
        .redirect(reqwest::redirect::Policy::none())
        .build()?;
    let (state, code) = extract_url(&url)?;
    let token = builder.get_user_token(&client, state.as_ref(), code.as_ref()).await?;
    println!("User token: {:?}", token);

Implementations§

Source§

impl UserTokenBuilder

Source

pub fn new( client_id: impl Into<ClientId>, client_secret: impl Into<ClientSecret>, redirect_url: Url, ) -> UserTokenBuilder

Create a UserTokenBuilder

§Notes

The redirect_url must be present, verbatim, on the Twitch Developer Console.

The url crate converts empty paths into “/” (such as https://example.com into https://example.com/), which means that you’ll need to add https://example.com/ to your redirect URIs (note the “trailing” slash) if you want to use an empty path.

To avoid this, use a path such as https://example.com/twitch/register or similar instead, where the url crate would not add a trailing /.

Source

pub fn set_scopes(self, scopes: Vec<Scope>) -> Self

Add scopes to the request

Source

pub fn add_scope(&mut self, scope: Scope)

Add a single scope to request

Source

pub fn force_verify(self, b: bool) -> Self

Enable or disable function to make the user able to switch accounts if needed.

Source

pub fn generate_url(&mut self) -> (Url, CsrfToken)

Generate the URL to request a code.

First step in the guide

Source

pub fn csrf_is_valid(&self, csrf: &str) -> bool

Check if the CSRF is valid

Source

pub fn get_user_token_request(&self, code: &str) -> Request<Vec<u8>>

Get the request for getting a TwitchTokenResponse, to be used in UserToken::from_response.

§Examples
use twitch_oauth2::{tokens::UserTokenBuilder, id::TwitchTokenResponse};
use url::Url;
let callback_url = Url::parse("http://localhost/twitch/register")?;
let mut builder = UserTokenBuilder::new("myclientid", "myclientsecret", callback_url);
let (url, _csrf_code) = builder.generate_url();

// Direct the user to this url.
// Later when your server gets a response on `callback_url` with `?code=xxxxxxx&state=xxxxxxx&scope=aa%3Aaa+bb%3Abb`

// validate the state
if !builder.csrf_is_valid(state_in_query) {
    panic!("state mismatched")
}
// and then get your token
let request = builder.get_user_token_request(code_in_query);

// use your favorite http client

let response: http::Response<Vec<u8>> = client_req(request);
let twitch_response = TwitchTokenResponse::from_response(&response)?;

// you now have a access token, do what you want with it.
// You're recommended to convert it into a `UserToken` via `UserToken::from_response`

// You can validate the access_token like this
let validated_req = twitch_response.access_token.validate_token_request();
Source

pub async fn get_user_token<'a, C>( self, http_client: &'a C, state: &str, code: &str, ) -> Result<UserToken, UserTokenExchangeError<<C as Client>::Error>>
where C: Client,

Available on crate feature client only.

Generate the code with the help of the authorization code

Last step in the guide

On failure to authenticate due to wrong redirect url or other errors, twitch redirects the user to <redirect_url or first defined url in dev console>?error=<error type>&error_description=<description of error>

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more