Kinde
Elixir SDK for Kinde authentication.
Implements OpenID Connect with PKCE for secure user authentication and provides a client for the Kinde Management API.
Installation
Add kinde to your list of dependencies in mix.exs:
def deps do
[
{:kinde, "~> 0.1.0"}
]
endConfiguration
# config/runtime.exs
config :kinde,
domain: "https://yourapp.kinde.com",
client_id: "your_client_id",
client_secret: "your_client_secret",
redirect_uri: "http://localhost:4000/callback"All configuration keys
Authentication (OIDC + PKCE)
| Key | Required | Default | Description |
|---|---|---|---|
:domain | yes | — |
Kinde domain (e.g. "https://yourapp.kinde.com") |
:client_id | yes | — | OAuth2 client ID |
:client_secret | yes | — | OAuth2 client secret |
:redirect_uri | yes | — | Callback URL after authentication |
:prompt | no | "login" |
OAuth2 prompt parameter ("login", "create", "none") |
:scopes | no | ["openid", "profile", "email", "offline"] | OAuth2 scopes |
These keys can also be passed directly to Kinde.auth/2 and Kinde.token/4 as a map, which takes precedence over app config.
Management API
Configured under the :management_api key:
config :kinde, :management_api,
client_id: "management_client_id",
client_secret: "management_client_secret",
business_domain: "https://yourapp.kinde.com",
req_opts: []| Key | Required | Default | Description |
|---|---|---|---|
:client_id | yes | — | Management API client ID |
:client_secret | yes | — | Management API client secret |
:business_domain | no |
value of :domain |
API base URL (falls back to top-level :domain) |
:req_opts | no | [] |
Extra options passed to Req.new/1 (e.g. custom plugins, adapters) |
If required keys are missing, the Management API server is not started (returns :ignore), and the rest of the application boots normally.
State management
| Key | Required | Default | Description |
|---|---|---|---|
:state_management_impl | no | Kinde.StateManagementAgent |
Module implementing Kinde.StateManagement behaviour |
Tesla adapter
Token verification fetches JWKS from Kinde's endpoint via JokenJwks, which uses Tesla under the hood. Configure a Tesla adapter in your application:
config :tesla, JokenJwks.HttpFetcher, adapter: {Tesla.Adapter.Finch, name: Finch}See the JokenJwks.HttpFetcher docs for details.
Testing
| Key | Required | Default | Description |
|---|---|---|---|
:test_strategy | no | false |
When true, uses Kinde.Test.TokenStrategy instead of JWKS verification (compile-time) |
Usage
Authentication (OIDC + PKCE)
1. Generate the authorization URL
# Using app config
{:ok, authorize_url} = Kinde.auth()
# With extra params (will be returned after token exchange)
{:ok, authorize_url} = Kinde.auth(%{}, %{return_to: "/dashboard"})
# With explicit config (overrides app env)
{:ok, authorize_url} = Kinde.auth(%{
domain: "https://yourapp.kinde.com",
client_id: "...",
client_secret: "...",
redirect_uri: "http://localhost:4000/callback"
})
Redirect the user to authorize_url. Kinde will redirect back to your redirect_uri with code and state query parameters.
2. Exchange the code for user data
{:ok, user_params, extra_params} = Kinde.token(code, state)
# user_params:
# %{
# id: "kp_abc123...",
# given_name: "Jane",
# family_name: "Doe",
# email: "jane@example.com",
# picture: "https://..."
# }
# extra_params — the map passed to Kinde.auth/2
# %{return_to: "/dashboard"}Management API
The Management API client starts automatically with the application and maintains its own access token via client credentials flow.
{:ok, user} = Kinde.ManagementAPI.get_user("kp_abc123")
{:ok, users} = Kinde.ManagementAPI.list_users()
# Handles pagination automatically, returns a flat listState management
OAuth state and PKCE code verifiers are stored in-memory via Kinde.StateManagementAgent (an Agent). This works for single-node deployments.
For multi-node setups, implement the Kinde.StateManagement behaviour and configure it:
config :kinde, :state_management_impl, MyApp.EctoStateManagement
See Kinde.StateManagement module documentation for a full Ecto-based example.
take_state/1 must read and delete the entry (one-time use).
Testing
The library ships with Kinde.Test.TokenStrategy that signs tokens with a local RSA key instead of verifying against Kinde's JWKS endpoint. Enable it in your test config:
# config/test.exs
config :kinde, test_strategy: true
Use Req.Test to stub HTTP requests in tests. See test/kinde_test.exs for examples.
License
See LICENSE for details.