OAuth 2.0 authorization and token exchange
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

OCaml 97.8%
Dune 0.6%
Other 1.6%
64 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-oauth https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-oauth
git@git.recoil.org:gazagnaire.org/ocaml-oauth git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-oauth

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

oauth#

Generic OAuth 2.0 authorization and token exchange for OCaml.

Overview#

Implements the OAuth 2.0 Authorization Code grant (RFC 6749) with PKCE support (RFC 7636). Provides state generation for CSRF protection, authorization URL construction, and token exchange/refresh. Supports multiple providers out of the box: GitHub, Google, GitLab, and custom providers.

Features#

  • Multi-provider -- GitHub, Google, GitLab, and custom OAuth providers
  • PKCE -- RFC 7636 code challenge/verifier for native apps
  • State validation -- Constant-time CSRF state comparison
  • Token exchange -- Makes HTTP calls via Requests.t
  • Token refresh -- Automatic refresh token handling
  • Userinfo parsing -- Provider-specific user profile parsing
  • Redirect URI validation -- HTTPS enforcement, no fragments (RFC 8252)

Installation#

Install with opam:

$ opam install oauth

If opam cannot find the package, it may not yet be released in the public opam-repository. Add the overlay repository, then install it:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install oauth

Usage#

(* 1. Before redirect: generate state and PKCE *)
let run http callback_state code =
  let redirect_uri =
    Oauth.redirect_uri "https://app.com/callback" |> Result.get_ok
  in
  let state = Oauth.generate_state () in
  let verifier = Oauth.generate_code_verifier () in
  let challenge = Oauth.code_challenge S256 verifier in
  (* Store [state] and [verifier] in the user's session. *)
  let _url =
    Oauth.authorization_url Github ~client_id:"xxx" ~redirect_uri ~state
      ~scope:[ "user:email" ] ~code_challenge:challenge ()
  in
  (* Redirect user to [_url]. *)

  (* 2. On callback: validate state, then exchange code *)
  if not (Oauth.validate_state ~expected:state ~actual:callback_state) then
    failwith "CSRF state mismatch";
  let client_auth =
    Oauth.Client_auth.basic ~client_id:"xxx" ~client_secret:"yyy"
  in
  match
    Oauth.exchange_code http Github ~client_auth ~code ~redirect_uri
      ~code_verifier:verifier ()
  with
  | Ok token -> Printf.printf "Access token: %s\n" token.access_token
  | Error e -> Fmt.epr "Error: %a@." Oauth.pp_parse_token_error e

API#

Providers#

  • Oauth.Github / Google / Gitlab -- Built-in providers
  • Oauth.custom_provider -- Define a custom OAuth provider (validates HTTPS)

Authorization#

  • Oauth.authorization_url -- Build provider-specific authorization URL
  • Oauth.generate_state -- Cryptographically secure CSRF state
  • Oauth.validate_state -- Constant-time state comparison
  • Oauth.redirect_uri -- Validated redirect URI (HTTPS, no fragments)

PKCE#

  • Oauth.generate_code_verifier -- Random code verifier
  • Oauth.code_challenge -- S256 code challenge from verifier

Token Exchange#

  • Oauth.exchange_code -- Exchange authorization code for tokens (HTTP POST)
  • Oauth.refresh_token -- Refresh an expired access token (HTTP POST)

Userinfo#

  • Oauth.parse_userinfo -- Parse provider-specific user profile
  • Oauth.parse_github_emails -- Get verified primary email from GitHub

Standards#

Licence#

ISC