Developers › Apps & OAuth

Register a client

Developer Reference Register a client Three ways to get a client_id, and one set of rules about where LeadLogiX will send an authorization code. Registration is open — you do not need an account with us, an initial access token, or an approval, and none of those would give your client more access than registering yourself does. Step 2 of the OAuth journey . Next: Scopes & limits , before you write the authorize URL — a requested scope and a granted scope are different things.

Pick a registration method

Pick a registration method Method Use it when What you get Dynamic registration Your stack can POST once at install or build time. The normal choice. A client_id immediately, no approval step Client ID Metadata Document You would rather publish a document than store a credential. Your metadata URL is the client_id Preregistration Your platform cannot do either — some marketplaces require a fixed id up front. An id we create for you, on request

Dynamic registration

Dynamic registration RFC 7591. Open, unauthenticated, immediate. curl -X POST https://leadval.evas.live/idp/register \ -H "Content-Type: application/json" \ -d '{ "client_name": "Acme Pipeline", "redirect_uris": ["https://acme.example/oauth/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "openid email leads:read" }' # 201 Created # { "client_id": "…", "registration_access_token": "…", "allowedScopes": ["leads:read"], … } const res = await fetch("https://leadval.evas.live/idp/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ client_name: "Acme Pipeline", redirect_uris: ["https://acme.example/oauth/callback"], grant_types: ["authorization_code", "refresh_token"], response_types: ["code"], token_endpoint_auth_method: "none", // public client: PKCE is the proof scope: "openid email leads:read", }), }); const { client_id, registration_access_token } = await res.json(); import requests r = requests.post("https://leadval.evas.live/idp/register", json={ "client_name": "Acme Pipeline", "redirect_uris": ["https://acme.example/oauth/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", # public client: PKCE is the proof "scope": "openid email leads:read", }, timeout=10) r.raise_for_status() client = r.json() # client_id, registration_access_token, allowedScopes, … In the response Read it as client_id Your client. Embed it; it is not a secret. registration_access_token Re-reads the registration with GET . It cannot update or delete it — registration management is off, so register again if you need different metadata. allowedScopes The capability part of your requested scope , moved to a ceiling on your client; the OIDC part ( openid , email , profile ) stays in scope . Expected — request scopes at the authorization endpoint as normal. client_secret Never issued here. A self-registered client is public , and a secret you send is ignored: a secret shipped to an SPA or a native app is a secret in the world. Confidential clients ( client_secret_basic / client_secret_post ) exist for identity products that cannot send a code_challenge ; LeadLogiX mints those by hand. The scope you send back is a declaration, not an entitlement Registration echoes your requested scope verbatim. That is what the protocol says to do, and it means the value in your client record proves nothing about what you can obtain. What a token actually carries is decided at consent, against three separate limits — see Scopes & limits . Read the granted scope from the token response and behave accordingly.

Client ID Metadata Document

Client ID Metadata Document Your client_id is an https URL we fetch. Publish a JSON document with the same fields you would have POSTed, and use its URL as your client_id . There is nothing to store on your side and nothing to rotate. LeadLogiX fetches the document the first time it sees the id and caches it. The whole document, with every field that matters: GET https://acme.example.com/leadval-client.json { "client_id": "https://acme.example.com/leadval-client.json", "client_name": "Acme Sales Copilot", "redirect_uris": ["https://acme.example.com/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "openid leads:read", "application_type": "web" } client_id must equal the URL byte for byte Not equivalent — identical. A trailing slash, http where the URL says https , or the document served from a redirect target while the id names the redirect source, and authorization fails with invalid_client . This is the one mistake almost everybody makes first, and it is worth checking before anything else. Relatedly: the fetch does not follow redirects, so the id must be the URL that serves the JSON, not one that points at it. Refused in the document Why client_secret or client_secret_expires_at A document anyone can fetch cannot carry a secret. Its presence is refused rather than ignored. token_endpoint_auth_method of client_secret_basic , client_secret_post or client_secret_jwt Same reason. Use none — every client registered this way is public and authenticates with PKCE. Confidential clients exist, but LeadLogiX mints them; there is no self-service path to one. A URI-valued field that is relative, or not https Every URL in the document must be absolute and https, including the redirect URIs, under the same rules as the table below. Anything served with a non-200 status, or not as JSON The fetch is strict on purpose: a 301 to your real document, or an HTML error page returned with a 200, both fail closed. Nothing about your client is stored here — the document is the registration This is the practical difference from dynamic registration, and it cuts both ways. There is no record of you on our side to expire, to be swept as dormant, or to drift out of step with your own metadata: we re-fetch and re-validate the document instead of keeping a copy. So editing it changes your client — add a redirect URI and it works once the cache expires, no call to us. Equally, unpublishing it stops every new authorization immediately, which is how you retire a CIMD client. Tokens already issued are separate; those are revoked from Connected apps , by the person who granted them. The cache window is yours to set: we honour the Cache-Control: max-age (or Expires ) on your document, clamped to between 30 seconds and 24 hours, and use 30 seconds if you send neither. Serve a short max-age while you are iterating and a long one in production. A client that reads discovery finds client_id_metadata_document_supported: true in the authorization-server metadata, so an MCP client can register itself this way with no credential and no approval — nobody at LeadLogiX has to let it in. The fetch is rate limited, and that is not aimed at you Anyone who can reach the authorization endpoint can make this server fetch a URL of their choosing. The limits are per calling address and per target host, and LeadLogiX refuses to fetch itself on any hostname it answers on. A legitimate client fetches once and never notices.

Redirect URI rules

Redirect URI rules Where an authorization code may be delivered. Accepted Refused https://… — any host http://… on any hostname, including localhost http://127.0.0.1:PORT/… Anything that does not parse as a URL http://[::1]:PORT/… Wildcards or patterns — the match is exact http://localhost is refused; http://127.0.0.1 is accepted This surprises people, so it is worth the sentence: the carve-out for plain HTTP exists because a native app listening on the loopback interface has no network hop to intercept (RFC 8252 §7.3). localhost is a hostname, resolved by whatever the machine's resolver says — which is not a guarantee that the code stays on the machine that asked for it. Use the address literal. A registration containing a refused URI fails with invalid_client_metadata and the message names the offending entries, so you are never left guessing which one.

Removing a registration

Removing a registration You cannot delete your own; here is what does. The registration endpoint answers GET with your registration access token and nothing else — PUT and DELETE return 404 because registration management is switched off. That is deliberate: enabling DELETE also enables PUT , and a token that can rewrite its own redirect_uris is a larger risk than a registration nobody removes. What happens to an abandoned registration Detail A nightly sweep reports it Self-registered clients with no activity for 90 days are listed on every run of the platform's retention job. Removal is off until an operator turns it on The sweep reports and deletes nothing by default, so the first weeks produce a list somebody reads. Being called keeps it alive; merely being authorized does not Activity is the last time an authorization was used . A client somebody still calls is never reaped; one holding an authorization nobody has exercised for 90 days is. None of this applies to a metadata document There is no stored registration to abandon or reap — unpublish the document and no new authorization can start. Existing tokens are revoked from Connected apps . Ask and it goes sooner Contact support@evas.live — an operator deletion revokes every grant and purges the artifacts with it.

What every client must do

What every client must do Requirement Detail PKCE Mandatory for public clients , S256 only. There is no plain challenge method. A confidential client that LeadLogiX has curated may omit it — but only if it sends nonce , which is the countermeasure that replaces it (RFC 9700 §2.1.1). Exact redirect match The URI in the authorization request must be one of the registered strings, character for character. An unregistered one is refused without redirecting anywhere. Discovery Read endpoints from /.well-known/oauth-authorization-server rather than copying them from documentation. Refresh handling Rotation with no grace window. Store the new token before you use it — refresh rotation .

Preregistration

Preregistration When neither of the above is possible. Some marketplaces require a client id before any code runs. Contact support@evas.live with your application name, redirect URIs and the scopes you need. A preregistered client is registered by us with the scopes you were granted — not capped at a default — and appears to a customer exactly like any other application on the consent screen.