Zum Inhalt springen
AtheronDEVELOPERS
← SDKs and libraries

Ruby SDK

Install and use aton-network.

Melden Sie sich an, um Ihre eigene Test-Client-ID in den Beispielen zu sehen.

Coming soon. aton-network is not published on RubyGems yet, so the install line on this page does not work until it is. Until then, everything works over plain HTTP: pick cURL in any code block, or start from Endpoints.

atheron is Sign in with Atheron for Ruby: PKCE, the authorize address, the code swap, userinfo, webhook signatures, the events stream and the developer API client, on Ruby 3.1 and its standard library alone. A Rails engine and an OmniAuth strategy come with it.

Install

The SDK uses Net::HTTP, follows no redirects and gives every call ten seconds. To route its calls through your own client or a proxy, set AtonNetwork.transport to anything that answers call(method, url, headers, body).

bash
bundle add aton-network   # or: gem install aton-network

Sign somebody in

Build the address on your server and keep started.kept (the verifier, state and nonce) in their session.

# The authorize request is a page the person opens, not an API call. Build the address on your
# server: a fresh PKCE pair, state and nonce for this browser, then redirect them to it.
VERIFIER=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=\n')
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=\n')
STATE=$(openssl rand -hex 16)
echo "https://accounts.aton-network.org/oauth/authorize?response_type=code&client_id=$ATHERON_CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&scope=openid%20profile%20email&state=$STATE&code_challenge=$CHALLENGE&code_challenge_method=S256"
Beispielantwort302
(no body: the browser follows the redirect)

Handle the callback

finish_sign_in checks state in constant time, then swaps the code. Send the secret from a server app; leave it out in a public app.

For a whole web app on Rack's session, AtonNetwork::Auth does both ends and keeps the person: begin in your sign-in route, complete in your callback, user anywhere after and sign_out on a POST from your own site. The SDK's Rack sample app (samples/rack) is one file.

# Swap the code from the redirect for tokens, on your server. HTTP Basic carries your client ID and
# secret; the verifier proves this is the browser that started the sign-in.
curl https://accounts.aton-network.org/oauth/token \
  -u "$ATHERON_CLIENT_ID:$ATHERON_CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri=https://app.example.com/callback \
  -d code_verifier="$VERIFIER"
Beispielantwort200
{
  "access_token": "eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "openid profile email offline_access",
  "id_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IjIwMjYtMTAtMDEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmF0b24tbmV0d29yay5vcmciLCJzdWIiOiI5YTZk...",
  "refresh_token": "ath_rt_6Qm9..."
}

Read who it is now

# Who the person is as of now, with an access token issued to your client.
curl https://accounts.aton-network.org/oauth/userinfo \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Beispielantwort200
{
  "sub": "9a6d4c1e-1f0b-4a51-8a8e-3b2f6c0d7e11",
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "email_verified": true,
  "age": { "verified": true, "adult": true, "sixteen_or_over": true }
}

Keep them signed in

# A new access token and a new refresh token for the newest refresh token you hold. The old one stops working.
curl https://accounts.aton-network.org/oauth/token \
  -u "$ATHERON_CLIENT_ID:$ATHERON_CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token="$REFRESH_TOKEN"
Beispielantwort200
{
  "access_token": "eyJhbGciOiJFUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "openid profile email offline_access",
  "refresh_token": "ath_rt_k2Lp..."
}

Check a webhook

Pass the raw body, exactly as it arrived: request.raw_post in Rails, request.body.read in Rack.

Dieses Beispiel gibt es noch nicht in cURL. Gezeigt in TypeScript.

// Check that a webhook came from Atheron before you act on it. Pass the raw body, exactly as received.
import { verifyWebhook, type WebhookEvent } from "@aton-network/sdk";

export async function handleWebhook(request: Request): Promise<Response> {
  const raw = await request.text();
  const ok = await verifyWebhook(request.headers.get("atheron-signature"), raw, process.env.ATHERON_WEBHOOK_SECRET!);
  if (!ok) return new Response("bad signature", { status: 400 });
  const event = JSON.parse(raw) as WebhookEvent;
  if (event.type === "consent.revoked") {
    // Delete the refresh token you hold for event.data.sub, and stop using what you read.
  }
  return new Response(null, { status: 204 });
}

Follow the events stream

AtonNetwork::Events.follow reconnects when the connection drops and resumes after the last event it handed you; it stops only on a refusal that waiting cannot fix, such as a key without events:read. Without a block it answers an Enumerator. See the events stream.

# Follow the events stream. -N keeps curl from buffering; pass the last id you handled to resume.
curl -N https://developers.aton-network.org/api/v1/events \
  -H "Authorization: Bearer $ATHERON_API_KEY" \
  -H "Accept: text/event-stream" \
  -H "Last-Event-ID: $LAST_EVENT_ID"
Beispielantwort200
retry: 3000

event: ready
data: {"types":null}

id: 5b1c2a8e-0000-4000-8000-000000000001
event: user.signed_in
data: {"id":"5b1c2a8e-0000-4000-8000-000000000001","type":"user.signed_in","created":"2026-10-15T17:02:11.000Z","client_id":"live-1a2b3c4d5e6f7a8b","data":{"sub":"9a6d4c1e-1f0b-4a51-8a8e-3b2f6c0d7e11","scopes":["openid","email"],"at":"2026-10-15T17:02:11.000Z"}}

: beat

GraphQL

AtonNetwork::GraphQL runs queries on the standard library: query(AtonNetwork::GraphQL::USAGE_QUERY, { "days" => 30 }). The documents the SDK ships (the App, Usage, Overview and Events documents the GraphQL reference publishes) go as their SHA-256 alone, so the server knows them from the first request; your own go in full unless you turn persisted queries on. query raises AtonNetwork::GraphQL::FieldErrors when any field failed, with the data that could be read on it; request answers the data and the field errors side by side. Use AtonNetwork::Events.follow for events as they happen, or a WebSocket gem of your own with ws_close_action, ws_error_action and resume_variables.

Dieses Beispiel gibt es noch nicht in cURL. Gezeigt in TypeScript.

// Your app and its usage in one GraphQL request, then its events as they happen over the subscription.
// Node 22 has a global WebSocket; on Node 20, pass { WebSocket } from the ws package.
import { AtheronGraphQL, UsageQuery } from "@aton-network/sdk";

export async function usageThisMonth(apiKey: string): Promise<number> {
  const { usage } = await new AtheronGraphQL({ apiKey }).query(UsageQuery, { days: 30 });
  return usage ? usage.usage.reduce((sum, day) => sum + day.calls, 0) : 0;
}

export async function watchConsent(apiKey: string, lastId: string | null, forget: (sub: string | undefined) => void, signal?: AbortSignal): Promise<string | null> {
  for await (const event of new AtheronGraphQL({ apiKey }).events({ types: ["consent.revoked"], lastEventId: lastId, ...(signal ? { signal } : {}) })) {
    forget(event.data.sub);
    lastId = event.id; // keep it somewhere durable, to pass back after a restart
  }
  return lastId;
}

The developer API

# Your app as registered, for the environment this API key belongs to. Needs app:read.
curl https://developers.aton-network.org/api/v1/app \
  -H "Authorization: Bearer $ATHERON_API_KEY"
Beispielantwort200
{
  "name": "Price Check",
  "state": "live",
  "kind": "confidential",
  "quota": "free",
  "env": "live",
  "client_id": "live-1a2b3c4d5e6f7a8b",
  "redirect_uris": ["https://app.example.com/callback"],
  "scopes": ["openid", "profile", "email"],
  "approved_scopes": ["openid", "profile", "email"],
  "privacy_url": "https://app.example.com/privacy",
  "homepage_url": "https://app.example.com",
  "credentials": 2,
  "testers": 0,
  "webhooks": 1
}

Errors

Every failure is raised as AtonNetwork::Error with code (for example invalid_grant), description, the HTTP status and, on a 429, retry_after. See Errors for every code.

Frameworks

Rails and the OmniAuth strategy.

Fragen Sie Atlas

KI-Assistent

Fragen Sie alles zu Mit Atheron anmelden, zur API oder zum Portal. Die Antwort kommt aus unserer Dokumentation, mit Links zu den genutzten Seiten.