Module Requests_oauth.Oauth

RFC 6749 OAuth 2.0 Authorization Framework.

This module implements the OAuth 2.0 authorization framework as specified in RFC 6749.

Supported Grant Types

The Implicit Grant (Section 4.2) is intentionally not supported as it is deprecated per RFC 8996.

PKCE Support

This module supports Proof Key for Code Exchange (PKCE) per RFC 7636 to protect against authorization code interception attacks, especially for public clients.

Usage Example

  (* Client credentials grant *)
  let config = Oauth.make_config
    ~client_id:"my-client"
    ~client_secret:"my-secret"
    ~token_endpoint:"https://auth.example.com/token"
    () in
  match Oauth.client_credentials session config with
  | Ok token -> Printf.printf "Got token: %s\n" (Oauth.get_access_token token)
  | Error e -> Printf.printf "Error: %a\n" Oauth.pp_error e

  (* Authorization code flow with PKCE *)
  let pkce = Oauth.generate_pkce () in
  let state = Oauth.generate_state () in
  let auth_url = Oauth.authorization_url ~config ~state ~pkce () in
  (* ... redirect user to auth_url, receive code ... *)
  match Oauth.exchange_code session config ~code ~pkce_verifier:pkce.verifier () with
  | Ok token -> ...
  | Error e -> ...

References

Client Configuration

type config = {
  1. client_id : string;
    (*

    The client identifier issued during registration. Per Section 2.2.

    *)
  2. client_secret : string option;
    (*

    The client secret for confidential clients. None for public clients. Per Section 2.3.1.

    *)
  3. token_endpoint : string;
    (*

    The authorization server's token endpoint URL. Per Section 3.2.

    *)
  4. authorization_endpoint : string option;
    (*

    The authorization server's authorization endpoint URL. Required for Authorization Code grant. Per Section 3.1.

    *)
  5. redirect_uri : string option;
    (*

    The client's redirection endpoint for Authorization Code grant. Per Section 3.1.2.

    *)
  6. scopes : string list;
    (*

    The requested access token scope. Per Section 3.3.

    *)
}

OAuth 2.0 client configuration.

Per RFC 6749 Section 2, clients are identified by a client ID and optionally authenticated with a client secret.

val make_config : client_id:string -> ?client_secret:string -> token_endpoint:string -> ?authorization_endpoint:string -> ?redirect_uri:string -> ?scopes:string list -> unit -> config

make_config ~client_id ~token_endpoint ... creates an OAuth client configuration.

Token Types

type token = {
  1. access_token : string;
    (*

    The access token issued by the authorization server.

    *)
  2. token_type : string;
    (*

    The type of the token, typically "Bearer".

    *)
  3. expires_at : Ptime.t option;
    (*

    When the token expires. None if no expiry was provided.

    *)
  4. refresh_token : string option;
    (*

    The refresh token for obtaining new access tokens.

    *)
  5. scope : string option;
    (*

    The scope of the access token.

    *)
}

Token response from the authorization server. Per Section 5.1.

val get_access_token : token -> string

get_access_token token returns the access token string.

val get_refresh_token : token -> string option

get_refresh_token token returns the refresh token if present.

val is_expired : token -> bool

is_expired token returns true if the token has expired. Returns false if the token has no expiry information.

val expires_within : Ptime.Span.t -> token -> bool

expires_within span token returns true if the token expires within span. Returns false if the token has no expiry information.

Error Types

type error_code =
  1. | Invalid_request
  2. | Invalid_client
  3. | Invalid_grant
  4. | Unauthorized_client
  5. | Unsupported_grant_type
  6. | Invalid_scope
  7. | Unknown_error of string

OAuth 2.0 error codes per RFC 6749 Section 5.2.

type error = {
  1. code : error_code;
  2. description : string option;
  3. uri : string option;
}

OAuth error response.

val pp_error : Format.formatter -> error -> unit

Pretty printer for OAuth errors.

val error_code_to_string : error_code -> string

error_code_to_string code returns the RFC 6749 string representation.

PKCE Support

Per RFC 7636.

type pkce_method =
  1. | Plain
    (*

    code_challenge = code_verifier (not recommended)

    *)
  2. | S256
    (*

    code_challenge = BASE64URL(SHA256(code_verifier))

    *)

PKCE challenge method.

type pkce = {
  1. verifier : string;
    (*

    The code verifier (43-128 URL-safe characters).

    *)
  2. challenge : string;
    (*

    The code challenge derived from the verifier.

    *)
  3. method_ : pkce_method;
    (*

    The challenge derivation method.

    *)
}

PKCE state for authorization code flow.

val generate_pkce : ?method_:pkce_method -> unit -> pkce

generate_pkce () generates PKCE verifier and challenge. Default method is S256.

val pkce_method_to_string : pkce_method -> string

Returns "plain" or "S256".

State Parameter

val generate_state : unit -> string

generate_state () generates a cryptographically random state value for CSRF protection per RFC 6749 Section 10.12.

val validate_state : expected:string -> received:string -> bool

validate_state ~expected ~received performs constant-time comparison.

Authorization URL

val authorization_url : config:config -> state:string -> ?pkce:pkce -> ?extra_params:(string * string) list -> unit -> string

authorization_url ~config ~state () builds the authorization URL.

Token Operations

These functions use a Requests.t session to make HTTP calls.

val client_credentials : Requests.t -> config -> (token, error) result

client_credentials session config performs the client credentials grant. Per Section 4.4.

val password_grant : Requests.t -> config -> username:string -> password:string -> (token, error) result

password_grant session config ~username ~password performs the resource owner password credentials grant.

Per Section 4.3.

Warning: This grant type should only be used for legacy or high-trust scenarios.

val exchange_code : Requests.t -> config -> code:string -> ?pkce_verifier:string -> unit -> (token, error) result

exchange_code session config ~code () exchanges an authorization code for tokens. Per Section 4.1.3.

val refresh : Requests.t -> config -> refresh_token:string -> (token, error) result

refresh session config ~refresh_token exchanges a refresh token for a new access token. Per Section 6.

Managed Token State

Thread-safe automatic token refresh.

type t

Managed OAuth state with automatic token refresh.

val create : Requests.t -> config -> token -> ?on_refresh:(token -> unit) -> unit -> t

create session config token () creates managed OAuth state.

  • parameter on_refresh

    Optional callback when tokens are refreshed.

val get_token : t -> token

get_token t returns the current token, refreshing if needed. Thread-safe.

val get_access_token_managed : t -> string

get_access_token_managed t returns the current access token, refreshing if needed.

val force_refresh : t -> (token, error) result

force_refresh t forces a token refresh. Thread-safe.

val with_client_credentials : Requests.t -> config -> ?on_refresh:(token -> unit) -> unit -> (t, error) result

with_client_credentials session config () performs client credentials grant and returns managed state ready for use.