Skip to main content
Wildo.ai Coming soon

Machine and agent access

Give connected tools a standard authorization flow

Connected tools need a way to discover the application, request authorization and exchange credentials for tokens. Wildo provides those related endpoints as one authorization-server surface.

Discovery, authorization and token issuance lead an outside tool to agent access.

Give connected tools a standard authorization flow

Connected tools need a way to discover the application, request authorization and exchange credentials for tokens. Wildo provides those related endpoints as one authorization-server surface.

Registered services act under their own roles. User-approved tools receive access for a named agent endpoint, with identity information separated from operation permissions.

Example — A tool connects to an agent endpoint

The tool discovers the authorization endpoint, sends the person through approval and exchanges the returned code for a token bound to the requested agent resource.

For engineers

Discovery publishes the browser-facing consent URL, token endpoint, supported grants and signing-key information. The browser-facing authorization flow uses a registered redirect URI, state, a PKCE S256 challenge and the intended resource.

At exchange, the provider verifies the code against the original client, redirect and verifier before issuing anything:

This implementation excerpt from oauth-provider-token.backend.service.ts shows the decision in context; explanatory source comments are omitted.

const grant = await authCodeService.exchangeAuthorizationCode({
      code: request.code,
      clientId: request.clientId,
      redirectUri: request.redirectUri,
      codeVerifier: request.codeVerifier,
      presentedClientSecret: request.clientSecret,
    });

Build a public client’s authorization request

Use a registered public client with authorization-code access, an exact registered callback URI and an allowed MCP or A2A resource audience. Public registration uses PKCE rather than a client secret. A confidential client additionally authenticates at token exchange; do not place that secret in browser JavaScript.

This illustrative browser client uses metadata from a trusted, configured discovery URL. The browser must return to the same client origin/tab so its pending state remains available. A production client can use an OAuth library for this protocol bookkeeping; these functions expose the values that must stay connected.

async function beginDelegation({ discoveryUrl, clientId, redirectUri, resource }) {
  const response = await fetch(discoveryUrl);
  if (!response.ok) throw new Error(`Discovery HTTP ${response.status}`);
  const metadata = await response.json();
  const base64url = (bytes) => btoa(String.fromCharCode(...bytes))
    .replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '');
  const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
  const challenge = base64url(new Uint8Array(await crypto.subtle.digest(
    'SHA-256', new TextEncoder().encode(verifier),
  )));
  const state = base64url(crypto.getRandomValues(new Uint8Array(32)));
  sessionStorage.setItem('wildo-delegation', JSON.stringify({
    state, verifier, clientId, redirectUri, resource,
    tokenEndpoint: metadata.token_endpoint,
  }));

  const authorize = new URL(metadata.authorization_endpoint);
  authorize.search = new URLSearchParams({
    response_type: 'code', client_id: clientId,
    redirect_uri: redirectUri, scope: 'openid', state,
    code_challenge: challenge, code_challenge_method: 'S256',
    resource,
  }).toString();
  window.location.assign(authorize.href);
}

The discovered authorization endpoint is the frontend consent page. Wildo handles login and the person’s decision there. Its authenticated backend authorization/decision calls return JSON containing redirect_to; the frontend navigates to it. Your external client receives the callback, not the first-party session token or the internal consent token. Denial returns an error rather than a usable code. Consent may be bypassed only where the provider’s client/user policy permits it.

Validate the callback before exchanging its code

Run this on the registered callback page. This compact example allows one outstanding authorization attempt per tab; starting another replaces the pending attempt. It removes the pending entry before exchange, so a failed exchange starts a new authorization rather than replaying the code indefinitely.

async function finishDelegation() {
  const saved = sessionStorage.getItem('wildo-delegation');
  if (!saved) throw new Error('No pending authorization');
  const pending = JSON.parse(saved);
  const callback = new URL(window.location.href);
  const expected = new URL(pending.redirectUri);
  if (callback.origin !== expected.origin || callback.pathname !== expected.pathname
      || callback.searchParams.get('state') !== pending.state) {
    throw new Error('Authorization callback does not match the pending request');
  }
  sessionStorage.removeItem('wildo-delegation');
  if (callback.searchParams.has('error')) throw new Error('Authorization was not granted');
  const code = callback.searchParams.get('code');
  if (!code) throw new Error('Authorization returned no code');

  const response = await fetch(pending.tokenEndpoint, {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code', client_id: pending.clientId,
      redirect_uri: pending.redirectUri, code, code_verifier: pending.verifier,
      resource: pending.resource,
    }),
  });
  if (!response.ok) throw new Error(`Token exchange HTTP ${response.status}`);
  const token = await response.json();
  if (!token.access_token) throw new Error('Token exchange returned no access token');
  return { accessToken: token.access_token, expiresIn: token.expires_in, resource: pending.resource };
}

The token request reuses the original redirect URI and verifier. Its resource echo is optional in the server contract, but must match when supplied; the authorization code already binds the audience. Keep the returned access token in the client’s appropriate credential/session handling, out of URLs and logs. Call only the returned intended resource using the delegated agent-request example.

Keep the grant families distinct

FlowPrincipal and purpose
Client credentialsA registered service acting with its own roles
Authorization codeA consenting user delegating to a named MCP or A2A endpoint
Refresh tokenThe provider’s separate eligible session-refresh path

Authorization-code delegation does not issue an unrestricted first-party API session or a refresh token. It requires a valid agent resource audience. Identity scopes such as openid, email and profile control identity claims; they do not grant business operations.

Complete the browser handoff correctly

The frontend consent route is the browser authorization endpoint. The authenticated backend authorize call returns JSON containing redirect_to; the frontend navigates after receiving it. This avoids trying to follow a cross-origin client redirect inside an authenticated XHR.

Use interactive consent for the person’s decision, and machine clients when no person is delegating.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.