Using an AI assistant? Point it at 14a.dev/developers.md, the same guide as plain Markdown, or at 14a.dev/llms.txt.
One For All Auth: Developer Guide
Let your Even Hub app use a user's Groq AI or Spotify without asking them to paste API keys into your app.
The user sets up each service once on One For All Auth (https://14a.dev). Your app shows a short code. The user approves it, and your app is connected. Your app never sees their keys. The user can disconnect your app at any time.
Plain language, written so a person or an AI coding assistant can follow it top to bottom.
How it works (30 seconds)
- Your app calls
startConnect()and gets a code likeBCDF-GHJK. - You show the code on the phone screen and the glasses, plus an "Open approval page" button.
- The user approves on https://14a.dev/link (the button opens it with the code filled in).
login.doneresolves. You're connected, and this survives app restarts.- You call
ofa.chat("groq", …)orofa.spotify("/me/player/…").
There's no server to run, no client secret, and no redirect URLs.
Quick start
1. Get an app ID
Sign in at https://14a.dev/developer → Register a new app.
- Pick the services your app uses (Groq, Spotify).
- Copy the app ID it gives you, e.g.
lyrics-on-glasses-k3x9q2. It isn't secret; it goes in your code.
2. Add the SDK (one file)
Download these two files into your project's src/ folder:
- https://14a.dev/sdk/oneforall.js
- https://14a.dev/sdk/oneforall.d.ts (types, for TypeScript)
import { OneForAllAuth, OneForAllAuthError, SCOPES, evenHubStorage, createConnectButton } from "./oneforall.js";
It has no dependencies and works with plain Vite + TypeScript Even Hub projects.
3. Allow the network in app.json
"permissions": [
{
"name": "network",
"desc": "Connects to One For All Auth to use your AI and music services",
"whitelist": [
"https://oneforall-api.brandon-813.workers.dev",
"https://api.spotify.com"
]
}
]
Include https://api.spotify.com only if you use Spotify.
4. Connect and use it
import { waitForEvenAppBridge } from "@evenrealities/even_hub_sdk";
import { OneForAllAuth, OneForAllAuthError, SCOPES, evenHubStorage } from "./oneforall.js";
const bridge = await waitForEvenAppBridge();
const ofa = new OneForAllAuth({
clientId: "YOUR-APP-ID", // from step 1
storage: evenHubStorage(bridge), // keeps the login across restarts
optionalScopes: [SCOPES.GROQ, SCOPES.SPOTIFY], // or `scopes: [...]` if your app can't work without them
});
async function connect() {
const login = await ofa.startConnect();
showCode(login.userCode); // your UI: phone screen AND glasses
openButton.onclick = () => login.open(); // opens https://14a.dev/link with the code filled in
await login.done; // resolves once the user approves
}
if (!(await ofa.isConnected())) await connect();
// Groq: OpenAI-style chat completion
if (await ofa.hasScope(SCOPES.GROQ)) {
const res = await ofa.chat("groq", {
model: "llama-3.1-8b-instant",
messages: [{ role: "user", content: "One fun fact in under 30 words." }],
});
console.log(res.choices[0].message.content);
}
// Spotify: any Web API call, path after https://api.spotify.com/v1
if (await ofa.hasScope(SCOPES.SPOTIFY)) {
const r = await ofa.spotify("/me/player/currently-playing");
if (r.status === 204) console.log("Nothing playing");
else console.log((await r.json()).item?.name);
}
That's the whole integration. A full working example (phone UI plus glasses display) is in examples/even-groq/src/main.ts in the One For All Auth repo.
The Connect button
Use the official button, so users recognize it in every app.
Easiest: let the SDK make it. Its styles are built in, so no CSS is needed:
import { createConnectButton } from "./oneforall.js";
const button = createConnectButton({ onClick: connect });
document.querySelector("#connect-area")!.append(button);
Building your own? Match this exactly:
| Label | Connect with One For All Auth (use "Reconnect" wording only when reconnecting) |
| Background | #71e7eb (hover #8eedf0) |
| Text and icon | #131b24 (blue-gray off-black, not pure black) |
| Shape | 44px tall minimum, 10px rounded corners, 18px side padding |
| Font | 16px, bold (700), your app's system font |
| Icon | The One For All Auth dot mark, 18px tall, left of the label (brandMarkSvg() returns it as SVG) |
<button class="ofa-connect-button">
<!-- brandMarkSvg() output goes here -->
<span>Connect with One For All Auth</span>
</button>
<style>
.ofa-connect-button {
display: inline-flex; align-items: center; gap: 10px;
min-height: 44px; padding: 0 18px; border: 0; border-radius: 10px;
background: #71e7eb; color: #131b24; font: 700 16px/1 system-ui, sans-serif; cursor: pointer;
}
.ofa-connect-button:hover { background: #8eedf0; }
</style>
Please don't recolor it, stretch the icon, or change the wording.
What to show the user while connecting
Show the code on the glasses and the phone. Users can approve by reading the code off the glasses.
Connect One For All Auth
Code: BCDF-GHJK
Approve it on your phone.
On the phone, show:
- the code in large text
- an Open approval page button →
login.open() - a small line: "Or go to 14a.dev/link and enter the code" (for another device), using
login.verificationUri - a Cancel button →
login.cancel()
Codes expire after 10 minutes. If login.done rejects with expired_token, show a "Try again" button that calls connect() again.
Required vs optional services
| Option | Behavior |
|---|---|
scopes: [...] |
Required. The user can't approve until every one is set up on their account. |
optionalScopes: [...] |
Optional. If the user hasn't set one up, it's skipped. Your app connects with the rest. |
After connecting, check with await ofa.hasScope(SCOPES.GROQ). If an optional service is missing, tell the user:
"Groq isn't connected. Set it up at 14a.dev, then tap Reconnect."
and make Reconnect call connect() again. Reconnecting replaces the old connection automatically.
SDK reference
new OneForAllAuth(options)
| Option | Type | Notes |
|---|---|---|
clientId |
string | Your app ID. Required. |
storage |
TokenStorage |
Use evenHubStorage(bridge) in Even Hub apps. Required. |
scopes |
string[] | Required services. |
optionalScopes |
string[] | Optional services. |
apiUrl |
string | Leave unset. |
Methods
| Method | Returns | What it does |
|---|---|---|
isConnected() |
Promise<boolean> |
True if this app has a saved connection. |
startConnect() |
Promise<DeviceLogin> |
Starts the code login. Also used to reconnect. |
hasScope(scope) |
Promise<boolean> |
Whether the user granted that service. |
chat(provider, body) |
Promise<ChatCompletion> |
OpenAI-style chat completion. provider: "groq". |
spotify(path, init?) |
Promise<Response> |
Spotify Web API call; path is after /v1. |
getProviderToken("spotify") |
Promise<string> |
Raw 1-hour Spotify token, if you'd rather call Spotify yourself. |
fetch(path, init?) |
Promise<Response> |
Any One For All Auth API path with auth handled (advanced). |
proxyBaseUrl("groq") |
string | OpenAI-compatible base URL, for OpenAI client libraries (advanced; send requests with ofa.fetch). |
disconnect() |
Promise<void> |
Disconnects this app and forgets its login. |
Helpers
| Export | What it is |
|---|---|
createConnectButton({ onClick, label? }) |
The official Connect button, styled. |
brandMarkSvg(color?, size?) |
The One For All Auth mark as an SVG string. |
BRAND_COLOR, BRAND_INK |
#71e7eb and #131b24. |
DeviceLogin (from startConnect())
| Field | Notes |
|---|---|
userCode |
Show it on the phone and glasses. |
verificationUri |
https://14a.dev/link, for typing the code on another device. |
verificationUriComplete |
Same page with the code filled in. |
open() |
Opens verificationUriComplete. Returns false if blocked. |
done |
Resolves on approval; rejects with OneForAllAuthError otherwise. |
cancel() |
Stops waiting (done rejects with cancelled). |
Scopes
| Constant | Value | Service | Notes |
|---|---|---|---|
SCOPES.GROQ |
llm:groq |
Groq AI | Chat (chat("groq", …)). Speech-to-text via ofa.fetch("/v1/proxy/groq/openai/v1/audio/transcriptions", …). |
SCOPES.SPOTIFY |
spotify:playback |
Spotify | Now playing and play/pause/skip. Playback control needs Spotify Premium. |
Your app can only request scopes it registered in step 1.
Errors
Every SDK error is a OneForAllAuthError with a code:
code |
Meaning | What your app should do |
|---|---|---|
not_connected |
No login, or the user disconnected your app. | Show Connect. |
insufficient_scope |
This connection doesn't include that service. | "Set it up at 14a.dev, then tap Reconnect." |
credential_missing |
The user removed that service from their account. | Same as above. |
credential_expired |
Spotify needs reconnecting (every 180 days). | "Reconnect Spotify at 14a.dev." |
access_denied |
The user tapped Deny. | Show Connect again. |
expired_token |
The code expired (10 minutes). | Show Try again. |
cancelled |
You called login.cancel(). |
Nothing. |
rate_limited |
Too many requests (about 60 a minute per user). | Wait and retry. Don't poll faster than every few seconds. |
provider_error |
Groq or Spotify returned an error. | Show err.message. |
try {
await ofa.chat("groq", body);
} catch (err) {
if (err instanceof OneForAllAuthError && err.code === "not_connected") showConnectButton();
else showMessage(err instanceof Error ? err.message : "Something went wrong");
}
Rules (please follow)
- Never ask users for API keys. That's what One For All Auth replaces.
- Don't log or display tokens. The SDK handles them; you never need to touch them.
- Ask only for the services you use, and prefer
optionalScopesunless your app truly can't work without one. - Poll gently. "Now playing" every 3–5 seconds is fine; every second is not.
- Users see your app's name and description when approving, and can disconnect it any time.
Testing
- Use the Even Hub simulator. The approval page opens in your normal browser.
- New apps show an "unverified" warning on the approval page. That's expected.
- See your connection on https://14a.dev under Connected apps, and disconnect it there to test
not_connected.
Without the SDK (raw HTTP)
Base URL: https://oneforall-api.brandon-813.workers.dev. Form-encoded or JSON bodies.
POST /oauth/device/codewithclient_id,scope(space-separated, required),optional_scope(space-separated). Returnsdevice_code,user_code,verification_uri,verification_uri_complete,interval,expires_in.- Every
intervalseconds:POST /oauth/tokenwithgrant_type=urn:ietf:params:oauth:grant-type:device_code,device_code,client_id.400 {"error":"authorization_pending"}: keep waiting.slow_down: add 5 s to the interval.- Success returns
access_token(15 min),refresh_token,expires_in,scope.
- Renew:
POST /oauth/tokenwithgrant_type=refresh_token,refresh_token,client_id. Refresh tokens are single use. Save the new one every time; reusing an old one disconnects the app. - Call services with
Authorization: Bearer <access_token>:- Groq:
POST /v1/proxy/groq/openai/v1/chat/completions(alsoGET …/models,POST …/audio/transcriptions) - Spotify:
POST /v1/tokens/spotify→{ access_token, expires_at }, then callhttps://api.spotify.com/v1/...with it.
- Groq:
- Disconnect:
POST /oauth/revokewithtoken=<refresh_token>.
For AI coding assistants
When integrating One For All Auth into an Even Hub app:
- Copy
oneforall.js(andoneforall.d.ts) from https://14a.dev/sdk/ intosrc/. - Add the API host (and
https://api.spotify.comif using Spotify) toapp.json→permissions→network→whitelist. - Create
new OneForAllAuth({ clientId, storage: evenHubStorage(bridge), optionalScopes: [...] })afterwaitForEvenAppBridge(). - On start: if
!(await ofa.isConnected()), show the official Connect button (createConnectButton({ onClick })). On tap:startConnect(), showuserCodeon the phone and glasses, wire a button tologin.open(),await login.done. - Before using a service, check
hasScope(). If it's missing, show "set it up at 14a.dev, then Reconnect", with Reconnect callingstartConnect(). - Use
ofa.chat("groq", {...})for AI andofa.spotify("/me/player/...")for Spotify. - Catch
OneForAllAuthErrorand handlenot_connectedby showing Connect again. - Never store, log, or display tokens or keys.
Help
Questions, bugs, or want your app verified? Email brandon@scarletsocial.com.