Authentication and scopes | GlitchAds

Authentication and scopes

Two ways in: OAuth 2.1 for a person in an interactive client, API keys for automation. Both resolve to the same identity, the same scopes and the same audit trail.

OAuth 2.1, for interactive clients

When you add the server to an MCP client, the client discovers the authorization setup by itself and opens a browser. You sign in and approve the scopes. There is no manual registration and no client id to paste.

For anyone implementing a client, the server follows the current MCP authorization specification:

Protected resource metadata /.well-known/oauth-protected-resource/mcp (RFC 9728). An unauthenticated request answers 401 with a WWW-Authenticate header naming it. The path carries the resource path as a suffix, per the specification, so it is not the bare well-known URL.
Authorization server metadata Published per RFC 8414, at the location the resource metadata names.
Client registration Dynamic Client Registration (RFC 7591) and Client ID Metadata Documents are both supported, and the authorization server metadata says so. Nothing needs registering in advance. Clients are public, with no secret, and redirect URIs must be https, or http on localhost, and match exactly, apart from the port of a localhost redirect, which may differ (RFC 8252).
PKCE Required, S256. Authorization code flow only, and no implicit grant.
Resource indicators Clients must send resource per RFC 8707: https://mcp.glitchads.ai/mcp for the MCP server, or https://api.glitchads.ai/v1 for the REST API. A request without it is refused. Tokens are audience bound: one minted for the MCP server is refused by the REST API, and the other way round.
Tokens Access tokens live at most an hour, and refresh tokens rotate on use. A connection that goes 60 days without a refresh expires and has to be connected again. Bearer tokens go in the Authorization header on every request, never in a query string.
Token passthrough Forbidden. Glitch never accepts a token issued for another service, and never forwards yours anywhere, Google Ads included.
Revocation Token revocation per RFC 7009, at the revocation_endpoint the authorization server metadata names. Revoking a token ends the session it belongs to, and the connection itself once no session is left standing, so an app tidying up a credential it has replaced does not disconnect the one that replaced it. An access token from an ended session stops working at once rather than lasting out its hour. Ending the whole connection whatever is live is what revoking it in Glitch does, under Account, API Keys, Connected apps.

If an old refresh token is presented again, which is what replaying a stolen one looks like, the whole family is revoked and the client has to be authorised afresh. The one allowance is a retry: for 60 seconds after a refresh, the token it replaced is still accepted, so a client whose response was lost in transit is not disconnected for sending it again.

The consent screen

Consent asks which scopes to grant, and unchecking a scope narrows the grant to what stays checked. A client that names no scopes is offered all ten: uncheck any that your roles do not allow, or approval fails. The connection then covers every organization the account belongs to, capped in each by the role held there, and every request names the organization it acts in with membership checked live. For Glitch adops staff it also covers every client organization assigned to their team, read only, however many scopes were granted. An agency managing several client organizations holds one connection and names the client per request, or uses one API key per client where hard isolation per credential is wanted.

To change scopes, reconnect without removing the server. Reconnecting replaces the granted scopes with the ones approved on that screen, and the change takes effect from the client's next token refresh.

API keys, for automation

Keys are created in the platform under Account, API Keys. Any member of the organization can create one; the role ceiling below limits what a key can carry. Rotation and revocation belong to the key's creator or an Owner. The same key works on both surfaces.

curl https://api.glitchads.ai/v1/organizations/_/campaigns \
  -H "Authorization: Bearer glads_live_7Fq2xKpR4mNvB8sD3hJwL6tYzC1aEg9Qk4Xn"
Format Every key starts glads_live_. The glads_test_ prefix is reserved for sandbox keys, which are not available yet. A key is shown once at creation; afterwards only the prefix and the last four characters are displayed.
Scope Chosen at creation and never exceeding the role of the person creating it. A key is bound to one organization. If that person's role later drops below what the key carries, the key stops working and answers unauthorized: create a new one within the new role.
Expiry Every key expires one year after it is created. The person who created it is emailed 30 days and 7 days before.
Rotation Issues a replacement with the same name and scopes, and keeps the old key working for up to 48 hours, less if it expires sooner, which is the window to deploy the new one. The replacement belongs to the person who rotated it and expires a year later.
Revocation Immediate, and not reversible. A revoked key answers unauthorized on its next request.
Storage Only a SHA-256 hash is kept, so a key cannot be read back. Keep yours in a secret manager or an environment variable, and never commit one.

What a key looks like

glads_live_  7Fq2xKpR4mNvB8sD3hJwL6tYzC1aEg  9Qk4Xn
^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^
environment  30 random characters             checksum

The last six characters are a checksum of the thirty before them, so anything holding a string can tell whether it is a well formed Glitch key without sending a request. That is what lets an automated scanner recognise one in a commit. The sample on this page deliberately fails that check, so nothing ever mistakes it for a live credential.

Scopes

Every credential carries an explicit list of scopes, and every endpoint requires one. A request outside the granted list answers insufficient_scope and changes nothing.

Scopeorganizations:read GrantsYour organizations with your role in each, the account overview and the business profile. Toolsglitch_list_organizations, glitch_get_account_overview, glitch_get_business_profile
Scopecampaigns:read GrantsCampaign structures, their keywords, and running a detector. Toolsglitch_list_campaigns, glitch_get_campaign, glitch_list_keywords, glitch_run_detector
Scopeperformance:read GrantsMetrics and search terms. Toolsglitch_get_performance, glitch_get_search_terms
Scopereports:read
reports:generate
GrantsRetrieving a report or a strategy document, and asking for a new one. A strategy is minutes of work, so treat generate as the expensive half of this pair. Toolsglitch_get_report
glitch_generate_report
glitch_get_strategy
glitch_list_strategies
glitch_generate_strategy
Scoperecommendations:read GrantsWhat the engine and detector runs have proposed: pending, applied or dismissed. Toolsglitch_list_recommendations
Scoperecommendations:apply GrantsApplying a recommendation, and undoing any executed action, whichever tool made it. Toolsglitch_apply_recommendation, glitch_undo_action
Scopecampaigns:write GrantsBudgets, names, target CPA, states, draft campaigns and new ads. Toolsglitch_update_campaign, glitch_set_campaign_state, glitch_create_campaign, glitch_create_ad
Scopekeywords:write GrantsNegative keywords. Toolsglitch_add_negative_keywords
Scopeaudit:read GrantsThe action log, and exporting the audit trail. Toolsglitch_get_action_log

Polling a task is the one thing that needs no scope of its own: glitch_get_task_status and GET /v1/task-tracking/{task_id} accept any valid credential, because the id was handed to that caller in the first place.

Roles cap scopes

A token or a key can never do more than the person behind it. Your role in the organization sets the ceiling:

RoleMember Every read scope except audit:read, plus reports:generate.
RoleAdmin Everything a Member has, plus the write scopes.
RoleOwner Everything an Admin has, plus audit:read and rotation or revocation of any key in the organization, not only their own.

The ceiling applies to what you can grant, not only to what you can use: a Member cannot create a key that writes.

Membership is checked again on every request. Remove somebody from the organization and their tokens and keys stop working immediately, without anything being revoked by hand.

Sandbox

Sandbox keys, with the glads_test_ prefix, are not available yet. Every key created today is a live key acting on real data, so start with read scopes and use dry_run previews while building a workflow.

If a key is exposed

GlitchAds keys are built for GitHub secret scanning, and the partner registration is in progress. Once active, a key committed to a public repository is reported by GitHub, usually within seconds of the push.

Such a report is acted on without waiting for anyone to read it. The key is revoked immediately, and every Owner of the organization is emailed the name of the key, its last four characters and, when GitHub reports it, where it was found. The person who created the key is emailed only if they are an Owner.

There is nothing to undo, because a revoked key cannot be used. What is left to do is:

  • Create a replacement key and deploy it.
  • Remove the secret from the history of the repository, not only from the current files.
  • As an Owner, export the audit trail for the period the key was public, with GET /v1/organizations/{org}/audit/export and its from and to dates, and check every request made with that key's last four characters.

A key exposed somewhere GitHub cannot see is not detected. Revoke that one yourself, under Account, API Keys.