OAuth PKCE flow for "Sign in with HuggingFace".
Implements the full PKCE (Proof Key for Code Exchange) authorization code flow,
mirroring oauthLoginUrl and oauthHandleRedirect from @huggingface/hub.
Flow
- Generate a login URL:
HuggingfaceClient.oauth_login_url/1 - Redirect the user to that URL
- The user approves access on HuggingFace
- They are redirected back to your app with
?code=...&state=... - Call
HuggingfaceClient.oauth_handle_redirect/1with the code and state
Example (Phoenix LiveView)
# Step 1: Generate URL
{:ok, %{url: login_url, state: state, nonce: nonce}} =
HuggingfaceClient.oauth_login_url(
client_id: "my-app-id",
redirect_uri: "https://myapp.com/auth/callback",
scopes: "openid profile read-repos"
)
# Store state + nonce in session, redirect user to login_url
# Step 2: Handle callback
{:ok, result} = HuggingfaceClient.oauth_handle_redirect(
code: params["code"],
state: params["state"],
stored_state: session[:oauth_state],
nonce: session[:oauth_nonce],
client_id: "my-app-id",
client_secret: System.get_env("HF_CLIENT_SECRET"),
redirect_uri: "https://myapp.com/auth/callback"
)
# result.access_token — use for Hub API calls
# result.user_info — %{sub:, name:, email:, ...}
Summary
Functions
Handles an OAuth redirect callback and exchanges the code for tokens.
Generates an OAuth login URL with PKCE challenge.
Functions
@spec handle_redirect(keyword()) :: {:ok, map()} | {:error, Exception.t()}
Handles an OAuth redirect callback and exchanges the code for tokens.
Returns {:ok, %{access_token, expires_at, user_info, scope}}.
Required options
:code— thecodequery param from the redirect:state— thestatequery param from the redirect:stored_state— the state you generated and stored in session:code_verifier— the PKCE verifier you stored in session:client_id— OAuth app client ID:redirect_uri— must match the original redirect_uri
Optional
:client_secret— for confidential apps:nonce— for ID token verification
@spec login_url(keyword()) :: {:ok, map()} | {:error, Exception.t()}
Generates an OAuth login URL with PKCE challenge.
Returns {:ok, %{url: String.t(), state: String.t(), nonce: String.t(), code_verifier: String.t()}}.
You must persist state, nonce, and code_verifier (e.g. in the session)
for use in handle_redirect/1.