OAuth integration - Docs - PostHog

OAuth integration

Contents

PostHog supports OAuth 2.0 for third-party applications to access PostHog on behalf of users. This page explains how to integrate with PostHog's OAuth system.

OAuth server endpoints

PostHog's OAuth endpoints are available per-region, as well as through a region-agnostic domain that transparently handles routing between US and EU Cloud:

Region Base URL
US Cloud https://us.posthog.com
EU Cloud https://eu.posthog.com
Region-agnostic https://oauth.posthog.com

If you're building an integration that should work for any PostHog customer regardless of their region, use https://oauth.posthog.com. The well-known metadata endpoint works the same way for all three domains.

Client ID Metadata Document (CIMD)

If you're building an application that needs to integrate with PostHog's OAuth, we recommend using the Client ID Metadata Document (CIMD) approach.

With CIMD, you don't pre-register your OAuth client with PostHog. Instead:

  1. Your client_id is a URL on a domain you control (for example, https://myapp.example.com/oauth-client).
  2. You host a metadata document at that URL – a JSON file describing your client. PostHog fetches this document during the OAuth flow to learn about your application.
  3. The domain serves as your client's identity. Users will see the metadata you publish (including the name and, optionally, a logo) on the authorization screen.

Metadata document contents

The JSON document you host at your client_id URL should include at least:

{
  "client_id": "https://myapp.example.com/oauth-client",
  "client_name": "My App",
  "logo_uri": "https://myapp.example.com/logo.png",
  "redirect_uris": ["https://myapp.example.com/oauth/callback"]
}

For native apps that grab a dynamically assigned local port at runtime (per RFC 8252), register a loopback redirect URI without a port – for example http://localhost/callback or http://127.0.0.1/callback – and a request on any port, like http://localhost:54321/callback, will match. If you register a localhost URI with a port, the request must use that exact port. 127.0.0.1 and ::1 allow any port regardless of what you register.

PostHog caches your metadata document according to the Cache-Control: max-age header you return. If you add a new redirect URI after your client has already been used, the previously cached document stays in effect until its TTL elapses. Return a shorter max-age to have changes picked up sooner.

See the OAuth Client ID Metadata Document draft for the full specification.

Server metadata discovery

Authorization server metadata

PostHog exposes its OAuth server configuration through the standard well-known metadata endpoint (RFC 8414):

Example:

curl https://oauth.posthog.com/.well-known/oauth-authorization-server

The response contains the endpoints and capabilities you need, including:

Protected resource metadata

PostHog also serves OAuth 2.0 Protected Resource Metadata (RFC 9728) at:

Example:

curl https://oauth.posthog.com/.well-known/oauth-protected-resource

The response tells OAuth clients which authorization server issues tokens for PostHog's API:

OAuth clients and MCP-style agents discover this endpoint automatically through the WWW-Authenticate: Bearer resource_metadata="..." header returned on 401 responses. This lets a client that receives a 401 follow the metadata URL to find the correct authorization server without any prior configuration.

Supported scopes

The scopes available through OAuth are listed in the scopes_supported field of the metadata document and mirror the scopes available for personal API keys in our REST API. Request only the scopes your application actually needs – this is a security best practice and reduces friction for users on the authorization screen.

Going live and getting verified

Start with CIMD. For most integrations, hosting a metadata document on a domain you control is all you need to go live, and your app's name and logo appear on the authorization screen. There's no registration step to wait on.

Verification is optional and isn't required to go live. It removes the unverified application notice shown on the authorization screen.

What verification means

A verified badge means PostHog has confirmed the identity of the developer behind the app and reviewed the app's name, logo, and requested scopes for fit. It is an identity check in the style of publisher verification. It is not a security audit of your application and it is not an endorsement by PostHog.

What we check

We aim to approve requests on arrival, so make sure the following are true before you contact us:

Requesting verification

Open a support request in the app, choosing Authentication as the topic, and include:

Verification is granted per region. If your integration supports both us.posthog.com and eu.posthog.com, say so in your request so we can verify your app in both regions.

PostHog may remove verification if an app's scopes, branding, or behavior change materially, and you can re-request it at any time.

Link your app to a PostHog organization

We recommend adding a CIMD verification token to your metadata document. Create it in Organization settings → CIMD verification tokens and add it under the com.posthog namespace as com.posthog.verification_token. Linking your app to a PostHog organization raises your provisioning rate limits and surfaces the integration to that organization's admins. It is recommended but not required, and it doesn't affect the unverified notice on the authorization screen. See Link your partner app to a PostHog organization for the full walkthrough.

Declare your scopes

We also recommend declaring the OAuth scopes your app needs under com.posthog.scopes in your metadata document. This sets a scope ceiling, the maximum set of scopes any token for your app can carry, so a reviewer can see exactly what your app asks for. See Declare OAuth scopes for your app for details.

Have a question while integrating? Reach out to us.

Token types

PostHog OAuth uses the following token prefixes:

Token type Prefix Description
Access token pha_ Short-lived token for API access
Refresh token phr_ Long-lived token to obtain new access tokens

Both token types are automatically revoked if detected by GitHub secret scanning.