OAuth 2.0 authorization and token exchange
0
fork

Configure Feed

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

oauth: rewrite README — Github_oauth→Oauth, multi-provider, PKCE, HTTP deps

+64 -44
+64 -44
README.md
··· 1 - # github-oauth 1 + # oauth 2 2 3 - GitHub OAuth URL generation and token exchange helpers for OCaml. 3 + Generic OAuth 2.0 authorization and token exchange for OCaml. 4 4 5 5 ## Overview 6 6 7 - This library provides helpers for implementing GitHub OAuth 2.0 authorization flows. It supports both GitHub Apps (with token expiry and refresh tokens) and traditional OAuth Apps. 7 + Implements the OAuth 2.0 Authorization Code grant (RFC 6749) with PKCE support 8 + (RFC 7636). Provides state generation for CSRF protection, authorization URL 9 + construction, and token exchange/refresh. Supports multiple providers out of 10 + the box: GitHub, Google, GitLab, and custom providers. 8 11 9 12 ## Features 10 13 11 - - Cryptographically secure state generation for CSRF protection 12 - - Authorization URL generation with scope support 13 - - Token exchange request body generation (JSON) 14 - - Token response parsing (access tokens, refresh tokens, expiry) 15 - - Refresh token request body generation 14 + - **Multi-provider** -- GitHub, Google, GitLab, and custom OAuth providers 15 + - **PKCE** -- RFC 7636 code challenge/verifier for native apps 16 + - **State validation** -- Constant-time CSRF state comparison 17 + - **Token exchange** -- Makes HTTP calls via `Requests.t` 18 + - **Token refresh** -- Automatic refresh token handling 19 + - **Userinfo parsing** -- Provider-specific user profile parsing 20 + - **Redirect URI validation** -- HTTPS enforcement, no fragments (RFC 8252) 16 21 17 22 ## Installation 18 23 ··· 23 28 ## Usage 24 29 25 30 ```ocaml 26 - (* Generate authorization URL *) 27 - let state = Github_oauth.generate_state () in 28 - let url = 29 - Github_oauth.authorization_url ~client_id:"your_client_id" 30 - ~callback_url:"https://yourapp.com/callback" ~state ~scope:[ "repo" ] 31 + (* 1. Before redirect: generate state and PKCE *) 32 + let redirect_uri = 33 + Oauth.redirect_uri "https://app.com/callback" |> Result.get_ok 31 34 in 35 + let state = Oauth.generate_state () in 36 + let verifier = Oauth.generate_code_verifier () in 37 + let challenge = Oauth.code_challenge S256 verifier in 38 + (* Store [state] and [verifier] in the user's session *) 32 39 33 - (* After user authorizes, exchange code for token *) 34 - let body = 35 - Github_oauth.exchange_request_body ~client_id:"your_client_id" 36 - ~client_secret:"your_secret" ~code ~redirect_uri:"https://yourapp.com/callback" 40 + let url = 41 + Oauth.authorization_url Github ~client_id:"xxx" 42 + ~redirect_uri ~state 43 + ~scope:[ "user:email" ] ~code_challenge:challenge () 37 44 in 38 - (* POST body over HTTPS to Github_oauth.access_token_url with headers: 39 - Content-Type: application/json 40 - Accept: application/json *) 45 + (* Redirect user to [url] *) 41 46 42 - (* Parse the response *) 43 - match Github_oauth.parse_token_response response_body with 44 - | Ok token -> 45 - Printf.printf "Access token: %s\n" token.access_token; 46 - (* For GitHub Apps, handle refresh *) 47 - (match token.refresh_token with 48 - | Some rt -> (* store for later refresh *) 49 - | None -> (* OAuth App, no refresh needed *)) 50 - | Error e -> 51 - Printf.eprintf "Error: %a\n" Github_oauth.pp_parse_token_error e 47 + (* 2. On callback: validate state, then exchange code *) 48 + if not (Oauth.validate_state ~expected:state ~actual:callback_state) then 49 + failwith "CSRF state mismatch"; 50 + 51 + match 52 + Oauth.exchange_code http Github ~client_id:"xxx" ~client_secret:"yyy" 53 + ~code ~redirect_uri ~code_verifier:verifier () 54 + with 55 + | Ok token -> Printf.printf "Access token: %s\n" token.access_token 56 + | Error e -> Fmt.epr "Error: %a@." Oauth.pp_error e 52 57 ``` 53 58 54 59 ## API 55 60 56 - - `Github_oauth.generate_state` - Generate CSRF protection state 57 - - `Github_oauth.authorization_url` - Build GitHub authorization URL 58 - - `Github_oauth.access_token_url` - Token exchange endpoint URL 59 - - `Github_oauth.exchange_request_body` - Build token exchange request 60 - - `Github_oauth.parse_token_response` - Parse token response JSON 61 - - `Github_oauth.refresh_request_body` - Build refresh token request 61 + ### Providers 62 62 63 - ## Standards 63 + - `Oauth.Github` / `Google` / `Gitlab` -- Built-in providers 64 + - `Oauth.custom_provider` -- Define a custom OAuth provider (validates HTTPS) 64 65 65 - - [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) - OAuth 2.0 66 - - [GitHub OAuth Documentation](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps) 66 + ### Authorization 67 67 68 - ## Related Work 68 + - `Oauth.authorization_url` -- Build provider-specific authorization URL 69 + - `Oauth.generate_state` -- Cryptographically secure CSRF state 70 + - `Oauth.validate_state` -- Constant-time state comparison 71 + - `Oauth.redirect_uri` -- Validated redirect URI (HTTPS, no fragments) 72 + 73 + ### PKCE 74 + 75 + - `Oauth.generate_code_verifier` -- Random code verifier 76 + - `Oauth.code_challenge` -- S256 code challenge from verifier 77 + 78 + ### Token Exchange 79 + 80 + - `Oauth.exchange_code` -- Exchange authorization code for tokens (HTTP POST) 81 + - `Oauth.refresh_token` -- Refresh an expired access token (HTTP POST) 82 + 83 + ### Userinfo 69 84 70 - - [github-oauth2](https://github.com/tmattio/ocaml-github-oauth2) - Full OAuth2 client with HTTP handling 71 - - [oauth2](https://opam.ocaml.org/packages/oauth2/) - Generic OAuth2 library 85 + - `Oauth.parse_userinfo` -- Parse provider-specific user profile 86 + - `Oauth.parse_github_emails` -- Get verified primary email from GitHub 87 + 88 + ## Standards 72 89 73 - This library focuses on URL and request body generation without HTTP dependencies, allowing integration with any HTTP client (Cohttp, Dream, Eio, etc.). 90 + - [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) -- OAuth 2.0 91 + - [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) -- PKCE 92 + - [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252) -- OAuth for Native Apps 93 + - [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750) -- Bearer Token Usage 74 94 75 95 ## Licence 76 96 77 - MIT License. See [LICENSE.md](LICENSE.md) for details. 97 + ISC