All notable changes to this project are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.0.0 — 2026-07-22
First release of this fork of techgaun/auth0_ex, whose last release was 0.9.0 in March 2024. Everything below is relative to that.
This release is not drop-in compatible with auth0_ex. See Migrating.
Changed
- Renamed throughout. The OTP application is
:auth0_client, the module namespace isAuth0Client, and the config key isconfig :auth0_client. The repository has beenauth0_clientsince the fork; the code now matches it. - Req replaces HTTPoison. hackney leaves the dependency tree entirely, along with the EOL 1.x
advisories it carried, and the
httpoison ~> 2.2constraint that blocked consumers from moving to httpoison 3.0. TLS trust now comes from OTP's system CA store via Mint rather than fromcertifi. - One failure value. Every function returns
{:ok, term},:ok, or{:error, %Auth0Client.Error{}}. The struct carriesreason,status,bodyandheaders, and is an exception, soraiseworks. This replaces two different error shapes that were themselves a source ofFunctionClauseErrordownstream. - Error bodies are decoded maps, not raw JSON strings. Callers that ran
Jason.decode!/1on the body themselves must drop that call. - Every 2xx is a success, and a 2xx with an empty body is
:ok. Previously only 200 and 201 counted, which madeAction.deploy/1(202) look like a failure. - Response headers survive the parse, so
Auth0Client.Error.retry_after/1can read the rate-limit backoff on a 429. Auth0Client.Utils.mgmt_token/0returns{:ok, token} | {:error, reason}rather than raising on any non-success response. A management call against a rate-limited tenant now returns an error instead of crashing, and never reaches the endpoint.
Added
Management API coverage went from 55 to 253 of 451 endpoints, with 22 resource groups fully covered.
- RBAC —
Role, and theeffective-*lookups onUserthat resolve access inherited through groups Group, the other half of that story: group members, and the roles a group grantsOrganization— members, org-scoped roles, invitations, connections, client grantsAction, replacing the deprecatedRuleahead of its 2026-11-18 end of lifeConnectioncomplete, includingConnection.Scim(inbound provisioning) andConnection.DirectoryProvisioning(outbound sync)ClientandClientGrantcomplete, including credentials, so Private Key JWT works end to endGuardian— MFA factors, policies, enrollment tickets, and provider configurationCustomDomainandKey— domain verification, signing-key rotation, bring-your-own-keySessionandRefreshToken— inspect and revoke one rather than all of themJobcomplete — bulk user import and export, import viamultipart/form-dataGrant,Tenant,Log,EmailProvider,Ticket,ResourceServer,DeviceCredential,UserBlock
Authentication API coverage went from 3 to 21 endpoints, and all 11 documented /oauth/token grants are
now reachable.
- The authorization code flow, end to end —
Url.authorize/2,Token.auth_code/4, PKCE, refresh, revoke, and both logout URL builders - MFA —
Auth0Client.Authentication.Mfaplus themfa-otp,mfa-oobandmfa-recovery-codegrants, closing the gap where a login could reportmfa_requiredand nothing could act on it - Passwordless, Device Authorization Flow (for devices with no browser), Pushed Authorization Requests, native social token exchange, and global token revocation
- JWKS and OIDC discovery —
jwks/0andopenid_configuration/0
Other additions:
- A management token cache built for concurrency.
Auth0Client.TokenStaterenews before expiry rather than after, keeps one fetch in flight so a cold cache under load makes one request rather than one per caller, evicts a token Auth0 rejects with a 401 and replays the request once, and redacts the cached JWT frominspect/1. token_refresh_skewconfig, how many seconds before expiry to renew. Defaults to 60.- Per-request headers on every verb.
- A documentation set covering configuration, login, MFA, users, RBAC, organizations, applications, connections, actions, domains and keys and error handling.
Removed
Endpoints Auth0 has deprecated or retired are not supported.
Auth0Ex.Management.Rule— deprecated 2023-05-16, read-only since 2024-11-18, end of life 2026-11-18. UseAuth0Client.Management.Action.Auth0Ex.Authentication.Login—database/6(POST /oauth/ro, deprecated 2017) andsocial/4(POST /oauth/access_token). Use the Resource Owner Password grant andUrl.authorize/2.Auth0Ex.Authentication.tokeninfo/1— superseded byuserinfo/1.Auth0Ex.Management.Blacklist—/blacklists/tokensis in neither the OpenAPI document nor the docs.- The
:v2_searchconfig flag — user search v2 was retired 2019-06-30.
Fixed
userinfo/1sent the access token in the query string, where it leaked into access logs. It is now anAuthorization: Bearerheader, the only form Auth0 documents.auth_code_pkce/5required aclient_secret, which public clients do not have — the entire reason PKCE exists. Nowauth_code_pkce/4, with the secret optional inopts.search_engine=v3was sent on everyUsercall, including ones that reject it. It is now applied inUser.all/1only, and an explicitsearch_enginewins.UserBlock.unblock/1always raisedBadMapError.build_url/2appended a trailing?when there was no query string, and raisedBadMapErroron a keyword list.http_optscould silently disable TLS certificate verification.verify: :verify_noneis now refused, withdangerously_disable_tls_verification: trueas an explicit, loudly-named opt-out.
Migrating from auth0_ex
# mix.exs
{:auth0_client, "~> 1.0"}# in your application
sed -i 's/Auth0Ex/Auth0Client/g' lib/**/*.ex
sed -i 's/:auth0_ex/:auth0_client/g' config/*.exs
Then, in order of how quietly each one fails:
- The config key is silent when missed.
config :auth0_exis simply never read, and the first call raises about a missing domain rather than about the rename. - Error handling changes shape. Match on
{:error, %Auth0Client.Error{}}and drop anyJason.decode!/1you were applying to the body — it raises on an already-decoded map. - Removed modules — see above for the replacement of each.
auth_code_pkce/5is now/4, andsignup/4takes(client_id, password, connection, opts)withemailinopts. Both changed shape rather than name; a guard turns an unmigratedsignupcall into aFunctionClauseErrorrather than a wrong request.