oauth

OAuth 2.0 client library for Kit

Files

FileDescription
.editorconfigEditor formatting configuration
.gitignoreGit ignore rules for build artifacts and dependencies
.tool-versionsasdf tool versions (Zig, Kit)
LICENSEMIT license file
README.mdThis file
examples/client-credentials.kitDry-run client credentials example
examples/github.kitDry-run GitHub authorization code example
kit.tomlPackage manifest with metadata, capabilities, and tasks
src/oauth.kitOAuth 2.0 client implementation
tests/oauth.test.kitFunctional tests for OAuth helpers
tests/types.test.kitType and constant behavior tests

Dependencies

No Kit package dependencies.

This package uses Kit's built-in HTTP and Time modules. The package manifest requests the net capability because token exchange and authenticated request helpers perform HTTP calls.

Installation

kit add gitlab.com/kit-lang/packages/kit-oauth.git

Usage

import Kit.Oauth as OAuth

main = fn =>
  config = OAuth.github "client-id" "client-secret" "http://localhost:3000/callback" ["read:user", "user:email"]

  state = OAuth.generate-state
  auth-url = OAuth.authorize-url config state

  println "Open this authorization URL:"
  println auth-url

main

Authorization Code

After the provider redirects back to your callback URL, validate that the returned state matches the state you generated, then exchange the authorization code for tokens:

match OAuth.exchange-code config code
  | Ok tokens ->
    println "Token type: ${tokens.token-type}"
    println "Expires in: ${Int.to-string tokens.expires-in} seconds"
  | Err err ->
    println "OAuth error: ${err}"

Authorization Code with PKCE

Use PKCE for public clients such as desktop apps, mobile apps, and browser-based flows:

verifier = "abcdefghijklmnopqrstuvwxyz0123456789-._~abc"
state = OAuth.generate-state
auth-url = OAuth.authorize-url-pkce config state verifier

match OAuth.exchange-code-pkce config code verifier
  | Ok tokens -> println "Access token received"
  | Err err -> println "OAuth error: ${err}"

The current PKCE helper uses the plain challenge method. It is structured so it can move to S256 once a string SHA256 helper is available.

Client Credentials

Use client credentials for machine-to-machine authentication:

config = OAuth.custom "client-id" "client-secret" "https://auth.example.com/oauth/authorize" "https://auth.example.com/oauth/token" "https://app.example.com/oauth/callback" ["api:read", "api:write"]

match OAuth.client-credentials config
  | Ok tokens ->
    println "Access token received"
  | Err err ->
    println "OAuth error: ${err}"

Refresh Tokens

match OAuth.refresh-token config refresh-token
  | Ok tokens -> println "Refreshed access token"
  | Err err -> println "Refresh failed: ${err}"

Authenticated Requests

match OAuth.get "https://api.example.com/user" tokens.access-token
  | Ok response ->
    println "Status: ${Int.to-string response.status}"
    println response.body
  | Error err ->
    println "API error: ${err}"
json-body = "{\"name\":\"Kit\"}"

match OAuth.post "https://api.example.com/resources" json-body tokens.access-token
  | Ok response -> println "Created: ${Int.to-string response.status}"
  | Error err -> println "API error: ${err}"

Provider Presets

Built-in provider helpers return an OAuthConfig with provider authorization and token endpoints filled in:

HelperProvider
OAuth.githubGitHub
OAuth.googleGoogle
OAuth.microsoftMicrosoft Entra ID / Azure AD
OAuth.discordDiscord
OAuth.slackSlack
OAuth.gitlabGitLab
OAuth.customAny OAuth 2.0 provider

Security Notes

  • Always validate the callback state value before exchanging an authorization code.
  • Use HTTPS redirect URIs in production.
  • Do not log access tokens, refresh tokens, authorization codes, or client secrets.
  • Store refresh tokens in secure storage appropriate for your application.
  • Use environment variables or a secret manager for client secrets.
  • Treat the checked-in examples as dry-run examples. They are designed to be parity-safe and do not contact live OAuth providers.

Development

Running Examples

Run examples with the interpreter:

kit run examples/github.kit
kit run examples/client-credentials.kit

Compile an example to a native binary:

kit build examples/github.kit && ./github

Running Tests

Run the test suite:

kit test

Run the test suite with coverage:

kit test --coverage

Running kit dev

Run the standard development workflow:

kit dev

This will:

  1. Check formatting
  2. Type-check source files in src/
  3. Type-check examples in examples/
  4. Run tests in tests/ with coverage

Running Parity

Run interpreter/compiler parity checks for the examples:

kit parity --no-spinner --failures-only

The examples use deterministic output and avoid live network calls so parity can compare interpreter and compiled executable output reliably.

Generating Documentation

Generate API documentation from doc comments:

kit doc

Note: Kit sources with doc comments (##) will generate HTML documents in docs/*.html.

Cleaning Build Artifacts

Remove generated files, caches, parity results, docs, lock files, and native build artifacts:

kit task clean

Note: Defined in kit.toml.

Local Installation

To install this package locally for development:

kit install

This installs the package to ~/.kit/packages/@kit/oauth/, making it available for import as Kit.Oauth in other projects.

License

This package is released under the MIT License - see LICENSE for details.

Exported Functions & Types

authorize-url

OAuthConfig -> String -> String

authorize-url-pkce

OAuthConfig -> String -> String -> String

exchange-code

OAuthConfig -> String -> Result TokenResponse String

exchange-code-pkce

OAuthConfig -> String -> String -> Result TokenResponse String

refresh-token

OAuthConfig -> NonEmptyString -> Result TokenResponse String

client-credentials

OAuthConfig -> Result TokenResponse String

get

NonEmptyString -> NonEmptyString -> Result HttpResponse String

post

NonEmptyString -> String -> NonEmptyString -> Result HttpResponse String

github

NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

google

NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

microsoft

NonEmptyString -> NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

discord

NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

slack

NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

gitlab

NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

custom

NonEmptyString -> NonEmptyString -> NonEmptyString -> NonEmptyString -> NonEmptyString -> List String -> OAuthConfig

generate-state

String

is-expired?

TokenResponse -> Int -> Bool