oauth2 Rust Library

repository·main·Indexed 22 days ago

https://github.com/ramosbugs/oauth2-rs

An extensible, strongly-typed Rust implementation of the OAuth2 protocol (RFC 6749). It provides tools for client and authorization server interactions, supporting flows such as Authorization Code, Client Credentials, Device Authorization (RFC 8628), Resource Owner Password Credentials, and Refresh Token. The library utilizes the builder pattern and typestates to enforce configuration requirements at compile time and includes optional integration with reqwest for asynchronous and synchronous HTTP requests.

Tokens
16.6K
Snippets
44
Records
69
Agent score
77%

What's inside oauth2

  1. Overview of the oauth2 crate

    main

    The oauth2 crate provides an extensible, strongly-typed implementation of the OAuth2 protocol (RFC 6749). It is designed to be used as a foundation for OAuth2 flows in Rust applications.

    Note for Authentication Use Cases: If you are implementing authentication (such as single sign-on or social login), it is recommended to use the openidconnect crate instead, as it is built on top of this crate and specifically handles OpenID Connect flows.

  2. Implement and use stateful HTTP clients

    main

    The 5.0 release replaces stateless function pointers with AsyncHttpClient and SyncHttpClient traits. This allows for reusing connections (e.g., using a reqwest::Client).

    Security Warning: To prevent SSRF vulnerabilities, configure your HTTP client not to follow redirects (e.g., use redirect::Policy::none in reqwest).

    Async Clients

    AsyncHttpClient is implemented for:

    • reqwest::Client (with reqwest feature enabled).
    • Any function: Fn(HttpRequest) -> F where F: Future<Output = Result<HttpResponse, E>>.

    Sync Clients

    SyncHttpClient is implemented for:

    • reqwest::blocking::Client (with reqwest-blocking feature enabled).
    • ureq::Agent (with ureq feature enabled).
    • oauth2::CurlHttpClient (with curl feature enabled).
    • Any function: Fn(HttpRequest) -> Result<HttpResponse, E>.
  3. Configure Client typestates for 5.x

    main

    In 5.0, Client uses typestates to ensure required endpoints are configured before an auth flow is used. All endpoints are now optional.

    1. Update Constructor

    Use the single-argument Client::new(client_id) constructor. Use setters like set_auth_uri() or set_token_uri() to configure the client.

    2. Handle Generic Parameters

    If you store a BasicClient or Client in a custom data type, you must include the five endpoint typestate generic parameters. The possible states are:

    • EndpointNotSet: Endpoint is unavailable.
    • EndpointSet: Endpoint is ready for use.
    • EndpointMaybeSet: Endpoint can be used via fallible methods that return Err(ConfigurationError::MissingUrl(_)) (useful for dynamic discovery).

    If using BasicClient, add these parameters: HasAuthUrl, HasDeviceAuthUrl, HasIntrospectionUrl, HasRevocationUrl, HasTokenUrl.

    // Example: Annotating a BasicClient with specific typestates
    type MyClient = BasicClient<
        EndpointSet,       // HasAuthUrl
        EndpointNotSet,    // HasDeviceAuthUrl
        EndpointNotSet,    // HasIntrospectionUrl
        EndpointNotSet,    // HasRevocationUrl
        EndpointSet,       // HasTokenUrl
    >;
  4. Enable synchronous reqwest in 5.x

    main

    In 5.0, the reqwest feature only enables the asynchronous client to reduce dependencies. To use the synchronous (blocking) reqwest client, you must explicitly enable the reqwest-blocking feature in your Cargo.toml.

    oauth2 = { version = "5", features = ["reqwest-blocking"] }
  5. Upgrade from 4.x to 5.x

    main

    The 5.0 release introduces several breaking changes to improve API consistency, type safety, and performance. Key changes include:

    • MSRV Update: The Minimum Supported Rust Version is now 1.71.
    • Typestate Client: Client now uses typestates to track which endpoints (like authorization or token URIs) have been set at compile time.
    • Stateful HTTP Clients: The crate now uses AsyncHttpClient and SyncHttpClient traits instead of stateless function pointers, allowing for connection reuse and custom client configuration.
    • Dependency Upgrades: Upgraded to http 1.0 and reqwest 0.12.
    • API Renaming: Endpoint getters and setters have been renamed for consistency with RFC terminology.
    • Type Changes: TokenResponse and TokenIntrospectionResponse now use an associated type TokenType instead of a generic parameter TT. Custom ErrorResponse implementations must now implement Display.
  6. Minimum Supported Rust Version (MSRV) requirements

    main

    The required Rust version depends on the major/minor version of the oauth2 crate you are using:

    • For 5.1 and newer releases: Rust 1.71
    • For 5.0.y releases: Rust 1.65
    • For 4.x releases: Rust 1.45

    Starting from version 5.0.0, the crate follows a policy of supporting Rust releases going back at least 6 months. MSRV changes occur during minor version updates and are not part of patch releases.

  7. How the Client uses Typestates and the Builder Pattern

    main

    The Client struct uses the Builder Pattern combined with Typestates to enforce OAuth2 requirements at compile time.

    Each endpoint (e.g., Authorization, Token, Revocation) has a corresponding generic type parameter (like HasAuthUrl) that tracks whether that endpoint has been configured.

    • EndpointNotSet: The default state. Methods requiring the endpoint are unavailable.
    • EndpointSet: The endpoint was configured using a direct setter (e.g., set_auth_uri()). Methods requiring this endpoint are available and return the requested object directly.
    • EndpointMaybeSet: The endpoint was configured using an optional setter (e.g., set_auth_uri_option()). Methods requiring this endpoint are available but return a Result<T, ConfigurationError> because the endpoint might be None at runtime.

    This allows the library to prevent common errors, such as attempting to exchange a code for a token before the token URI has been provided.

  8. Implement custom OAuth2 error responses using `ErrorResponse`

    main

    The ErrorResponse trait allows you to define how your application handles error responses from an OAuth2 provider. While the library provides StandardErrorResponse, you can implement ErrorResponse yourself to support non-standard-compliant providers or custom error formats.

    To implement ErrorResponse, your type must implement:

    • Debug
    • Display (for human-readable error messages)
    • serde::de::DeserializeOwned
    • serde::Serialize
  9. Implement the TokenIntrospectionResponse trait

    main

    The TokenIntrospectionResponse trait defines the standard fields returned by an OAuth2 introspection endpoint as per RFC 7662. You can implement this trait on your own custom response types to support non-standard or highly customized OAuth2 providers.

    Required Methods

    • active(&self) -> bool: Returns whether the token is currently active.
    • type TokenType: An associated type representing the token type.

    Optional Methods

    • scopes(&self) -> Option<&Vec<Scope>>: Space-delimited list of scopes.
    • client_id(&self) -> Option<&ClientId>: The client that requested the token.
    • username(&self) -> Option<&str>: The resource owner's identifier.
    • token_type(&self) -> Option<&Self::TokenType>: The type of token (e.g., Bearer).
    • exp(&self) -> Option<DateTime<Utc>>: Expiration timestamp.
    • iat(&self) -> Option<DateTime<Utc>>: Issued-at timestamp.
    • nbf(&self) -> Option<DateTime<Utc>>: Not-before timestamp.
    • sub(&self) -> Option<&str>: Subject of the token.
    • aud(&self) -> Option<&Vec<String>>: Intended audience.
    • iss(&self) -> Option<&str>: Issuer of the token.
    • jti(&self) -> Option<&str>: Unique identifier for the token.
  10. Implement a custom TokenResponse

    main

    To support non-standard OAuth2 providers or custom token fields, implement the TokenResponse trait and use StandardTokenResponse with a custom ExtraTokenFields type.

    StandardTokenResponse<EF, TT> includes standard fields like access_token, token_type, expires_in, refresh_token, and scopes, while flattening any fields defined in your EF (Extra Fields) implementation.

    Required trait methods for TokenResponse:

    • access_token(&self) -> &AccessToken (REQUIRED)
    • token_type(&self) -> &Self::TokenType (REQUIRED)
    • expires_in(&self) -> Option<Duration> (RECOMMENDED)
    • refresh_token(&self) -> Option<&RefreshToken> (OPTIONAL)
    • scopes(&self) -> Option<&Vec<Scope>> (OPTIONAL)
  11. Understand the Device Authorization Response structure

    main

    The DeviceAuthorizationResponse<EF> contains the data required to complete the device flow. Fields include:

    • device_code(): The device verification code.
    • user_code(): The code the end-user must enter on their device.
    • verification_uri(): The URL for the user to visit.
    • verification_uri_complete(): An optional URL that includes the user code for easier non-textual transmission.
    • expires_in(): The duration (as Duration) before the codes expire.
    • interval(): The minimum duration (as Duration) the client should wait between polling requests.
    • extra_fields(): Any additional fields defined by the ExtraDeviceAuthorizationFields trait.
  12. Use the Device Authorization Flow (RFC 8628)

    main

    The Device Authorization Flow is used for devices that lack a browser.

    1. Start Flow: Call exchange_device_code() on a client that has been configured with set_device_authorization_url(). This returns a DeviceAuthorizationRequest.
    2. Get Response: Execute the request to receive a DeviceAuthorizationResponse.
    3. Exchange for Token: Use exchange_device_access_token(auth_response) to exchange the device response for an access token.

    This requires the token endpoint to be set via set_token_uri() (or set_token_uri_option()).