---
title: "Authenticating to Scriptivox"
description: "Which credential an agent should use, how to obtain it, and how to hand it back."
canonical: "https://www.scriptivox.com/auth.md"
last-updated: "2026-08-29"
---

# Authenticating to Scriptivox

> Two credentials exist, for two different jobs. Pick by whether a human is
> present to approve access.

## Discover

Start from any protected endpoint and let the `401` tell you where to go.

1. Call it with no credential. The response carries
   `WWW-Authenticate: Bearer resource_metadata="..."`.
2. Fetch that URL — [https://www.scriptivox.com/.well-known/oauth-protected-resource](https://www.scriptivox.com/.well-known/oauth-protected-resource) — for RFC 9728 protected-resource
   metadata. Read `authorization_servers[0]`.
   Today that resolves to `https://gnyikikzcyrimwuxzbak.supabase.co/auth/v1`.
3. Fetch the RFC 8414 authorization-server metadata. A mirror carrying the
   `agent_auth` block is served at [https://www.scriptivox.com/.well-known/oauth-authorization-server](https://www.scriptivox.com/.well-known/oauth-authorization-server); the
   authorization server publishes its own authoritative copy at
   `<issuer>/.well-known/oauth-authorization-server`. Prefer the latter
   wherever the two could disagree.

Both documents carry an `agent_auth` block naming `identity_types_supported`
and a `revocation_uri`. There is deliberately **no `register_uri`** — see
[Register](#register).

## Pick a method

| | Use when | Section |
|---|---|---|
| **API key** | You are a script or a server the account owner controls. | [below](#1-api-key--for-a-script-or-a-server-you-control) |
| **OAuth 2.1** | You act on somebody else’s behalf and must not hold their key. | [below](#2-oauth-21--for-an-agent-acting-on-somebody-elses-behalf) |

If a human can paste a secret into your configuration once, use an API key —
it is one header and no redirects. If you are an MCP client, an assistant, or
anything a stranger will point at their own account, use OAuth.

## 1. API key — for a script or a server you control

A long-lived secret in the form `sk_live_...`, created by a signed-in user at
[https://platform.scriptivox.com/keys](https://platform.scriptivox.com/keys). Send it on every request as either:

```
Authorization: sk_live_...      (a Bearer prefix is also accepted)
X-Api-Key: sk_live_...
```

Base URL is `https://api.scriptivox.com/v1`. Full reference:
[https://platform.scriptivox.com/docs/authentication](https://platform.scriptivox.com/docs/authentication).
There is a ceiling of 5 keys per account. A key carries the full rights of the
account that owns it, so treat one as you would a password.

## 2. OAuth 2.1 — for an agent acting on somebody else’s behalf

Use this when you are an MCP client, an assistant, or any third-party app that
must not hold a user’s API key. The user approves once, in a browser, and you
receive a token scoped to their account.

Scriptivox is the **resource server**; the **authorization server** is the
Scriptivox Supabase project. Follow [Discover](#discover) to find it rather
than hard-coding the URL.

## Register

**There is no dynamic client registration.** The `agent_auth` block carries
no `register_uri`, and that omission is deliberate rather than an oversight:
RFC 7591 Dynamic Client Registration lets any caller mint an OAuth client
with no human in the loop, and this deployment does not want that surface.

An earlier version of this document promised DCR. It was wrong — the
authorization server advertises no `registration_endpoint`, and the
underlying path answers `403`. Ask for onboarding instead:

- Email [support@scriptivox.com](mailto:support@scriptivox.com) with your client name and
  redirect URIs, and you are issued a `client_id`.
- Or skip OAuth entirely: if the person can paste a secret once, an API key
  needs no registration at all.

## Claim

Once you hold a `client_id`, run the authorization code flow **with PKCE** —
the only flow supported.

1. Send the person to the `authorization_endpoint` with `response_type=code`,
   your `client_id`, your redirect URI, the scopes you need, and an S256
   `code_challenge`.
2. They land on the Scriptivox consent screen, see your registered name and
   the host your redirect URI points at, and approve or decline. Nothing is
   auto-approved.
3. Exchange the returned code at the `token_endpoint` with your
   `code_verifier`.

The `agent_auth` block advertises `identity_types_supported:
["identity_assertion"]`. There is **no `anonymous` type** — every token is
bound to a real, confirmed account. Inside `identity_assertion`,
`assertion_types_supported` names `urn:ietf:params:oauth:token-type:id-jag`
and `verified_email`.

## Use the credential

Send the access token as `Authorization: Bearer <token>`. Tokens are signed
by the authorization server; the `jwks_uri` in its metadata is how you verify
one if you need to.

### Scopes

The authorization server issues `openid`, `email`, `profile`, `phone` and
`offline_access`. The first four describe what you learn about the user; they
do **not** by themselves grant access to data. What a token can reach is
decided server-side, per registered client. Request the least you need.

`offline_access` is the one that matters for long-running work: it is what
yields a refresh token, so you do not lose access the moment the access token
expires and have to send the person back through consent.

### What a token cannot do

No OAuth token can start a transcription on the web app, at any scope. Web
plans include unlimited transcription and are priced for one human, so
programmatic transcription lives on the metered API instead — billed per hour
of audio, with no daily cap. This is enforced by there being no such
operation to call, not by a policy document.

## Errors

Every failure is `{"error": {"code": "...", "message": "..."}}` with a stable
machine-readable `code`. A `401` always carries `WWW-Authenticate`, which is
what makes [Discover](#discover) work from any endpoint. A `403` means the
credential was understood but is not allowed to do that. A `429` carries
`RateLimit-Policy` and `Retry-After`.

## Revocation

Stop using a credential the moment it is no longer needed — neither kind
expires on its own.

- **OAuth token.** POST it to the `revocation_uri` in the `agent_auth` block
  (`https://gnyikikzcyrimwuxzbak.supabase.co/auth/v1/oauth/revoke`), per RFC 7009. Revoking a refresh token ends
  the grant; the person can also revoke your client from their connections
  page at any time, without telling you.
- **API key.** Delete it at [https://platform.scriptivox.com/keys](https://platform.scriptivox.com/keys).
  Deletion takes effect immediately; there is no grace period and no way to
  recover the secret afterwards.

A revoked credential answers `401` with the same `WWW-Authenticate` challenge
as a missing one, so a long-running agent can simply re-enter
[Discover](#discover) rather than treating it as fatal.

## Related

- [https://www.scriptivox.com/.well-known/oauth-protected-resource](https://www.scriptivox.com/.well-known/oauth-protected-resource) — RFC 9728 metadata
- [https://www.scriptivox.com/.well-known/oauth-authorization-server](https://www.scriptivox.com/.well-known/oauth-authorization-server) — RFC 8414 mirror, with the `agent_auth` block
- [https://platform.scriptivox.com/docs/authentication](https://platform.scriptivox.com/docs/authentication) — API key reference
- [https://www.scriptivox.com/signup.md](https://www.scriptivox.com/signup.md) — creating the account in the first place
- [https://platform.scriptivox.com/.well-known/mcp](https://platform.scriptivox.com/.well-known/mcp) — MCP server manifest
