Create an OAuth client
Register an OAuth client and implement RevenueCat's authorization flow
This article shows you how to register an OAuth client and implement RevenueCat's authorization flow. You'll register the client, send developers through authorization, and call the REST API with the tokens you receive. By the end, your client can access RevenueCat on behalf of developers who approve it.
This page is for teams building an OAuth client that other RevenueCat developers will connect to. If you want to connect to an existing client, or revoke one you already authorized, see OAuth. If you're calling the REST API for your own project, create a secret API key instead.
How client authorization works
RevenueCat supports the OAuth 2.0 Authorization Code flow. Public clients must use Proof Key for Code Exchange (PKCE) (S256). Confidential clients can omit it. If a client sends a code_challenge, RevenueCat validates it. A RevenueCat developer approves your client on a consent screen, then your client receives an authorization code and exchanges it for an access token (atk_) and refresh token (rtk_).
OAuth tokens are developer-level: they can access the projects that developer owns or collaborates on, limited by the scopes they granted. Access tokens expire after 1 hour. Refresh tokens expire after 30 days. Refreshing rotates both tokens.
Client creation steps
- Register your client with RevenueCat Support. You'll get a client ID, and a client secret if the client is confidential.
- Send the developer through authorization. Direct them to the authorize endpoint, handle the redirect, and exchange the code for tokens.
- Call the REST API with the access token, and refresh when it expires.
Public clients must implement PKCE. Confidential clients can send it too. The rest of this page covers each of those in detail.
Client Registration
To integrate with RevenueCat's OAuth server, you'll need to register your application as an OAuth client. Contact our support team to register your client with the following information:
- Client Name: Display name for your application
- Client URI: Your application's homepage URL
- Redirect URIs: Valid callback URLs for your application
- Client Type: Public (for native/desktop apps) or Confidential (for server-side apps)
- Token auth method: Confidential clients use HTTP Basic authentication by default. Public clients use
none. If your integration requires sending credentials in the token request body, requestclient_secret_postwhen you register your client. - Scopes: Available scopes your application would like to request
Authorization Flow
Step 1: Initiate Authorization
Direct users to the authorization endpoint:
GET https://api.revenuecat.com/oauth2/authorize
Required Parameters:
client_id: Your client identifierresponse_type: Must becoderedirect_uri: Must match a registered redirect URIscope: Space-separated list of requested permissionsstate: Opaque value you generate and later compare to the redirect (required; omitting it returnsinvalid_request)code_challenge: PKCE code challenge (required for public clients, optional for confidential clients)code_challenge_method: Must beS256(required whencode_challengeis present)
Example Authorization URL:
https://api.revenuecat.com/oauth2/authorize?
client_id=your_client_id&
response_type=code&
redirect_uri=https://yourapp.com/callback&
scope=project_configuration:apps:read&
state=random_state_string&
code_challenge=your_code_challenge&
code_challenge_method=S256
Step 2: Handle Authorization Response
After the user grants permission, they'll be redirected to your redirect_uri. Confirm that state matches the value you sent in Step 1.
Success Response:
https://yourapp.com/callback?code=authorization_code&state=random_state_string
Error Response:
https://yourapp.com/callback?error=access_denied&error_description=description&state=random_state_string
Step 3: Exchange Code for Tokens
Exchange the authorization code for access and refresh tokens:
curl -X POST https://api.revenuecat.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "your_client_id:your_client_secret" \
-d "grant_type=authorization_code&code=your_auth_code&redirect_uri=https://yourapp.com/callback"
Parameters:
grant_type: Must beauthorization_codecode: The authorization code from Step 2redirect_uri: Must match the redirect URI from Step 1code_verifier: PKCE code verifier (required when acode_challengewas sent)
Confidential clients authenticate with the client ID and client secret using HTTP Basic authentication by default.
If your client is registered with client_secret_post, send client_id and client_secret in the form body
instead of using the Authorization header.
Success Response:
{
"access_token": "atk_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rtk_...",
"scope": "project_configuration:apps:read"
}
Token Management
Access Tokens
- Lifetime: 1 hour
- Usage: Include in API requests via
Authorization: Bearer {access_token}header - Prefix:
atk_
Refresh Tokens
- Lifetime: 30 days
- Usage: Exchange for new access tokens when they expire
- Prefix:
rtk_
Refreshing Tokens
When your access token expires, use the refresh token to get a new pair:
curl -X POST https://api.revenuecat.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "your_client_id:your_client_secret" \
-d "grant_type=refresh_token&refresh_token=your_refresh_token"
Parameters:
grant_type: Must berefresh_tokenrefresh_token: Your current refresh token
When tokens are refreshed, both the old access and refresh tokens are revoked, and new ones are issued. Make sure to update your stored tokens.
Available Scopes
Request only the scopes your application needs:
Project Configuration
project_configuration:projects:read- List projectsproject_configuration:projects:read_write- Create projectsproject_configuration:apps:read- Read apps and app configproject_configuration:apps:read_write- Create, update, and delete appsproject_configuration:entitlements:read- Read entitlements and attached productsproject_configuration:entitlements:read_write- Create, update, and delete entitlementsproject_configuration:offerings:read- Read offerings and paywallsproject_configuration:offerings:read_write- Create, update, and delete offerings and paywallsproject_configuration:packages:read- Read packages and attached productsproject_configuration:packages:read_write- Create, update, and delete packagesproject_configuration:products:read- Read productsproject_configuration:products:read_write- Create, update, delete, and push products to storesproject_configuration:integrations:read- List webhook integrationsproject_configuration:integrations:read_write- Create, update, and delete webhook integrationsproject_configuration:virtual_currencies:read- Read virtual currenciesproject_configuration:virtual_currencies:read_write- Create, update, and delete virtual currencies
Customer Information
customer_information:customers:read- Read customers, aliases, attributes, and active entitlementscustomer_information:customers:read_write- Manage customers and customer-level actionscustomer_information:subscriptions:read- Read subscriptions and related entitlements or transactionscustomer_information:subscriptions:read_write- Manage subscriptions, including cancellations and refundscustomer_information:purchases:read- Read purchases and purchase entitlementscustomer_information:purchases:read_write- Manage purchases and virtual currency balance operationscustomer_information:invoices:read- Read customer invoices
Charts & Metrics
charts_metrics:overview:read- Read overview metrics for a projectcharts_metrics:charts:read- Read chart data and options for a chart
Making API Requests
OAuth access tokens authenticate REST API v2 requests. Don't configure the RevenueCat SDK with an OAuth token. For your own app or backend, use API keys instead.
Include the access token in the Authorization header, using the same Bearer format as a secret API key:
curl -H "Authorization: Bearer atk_your_access_token" \
https://api.revenuecat.com/v2/projects
PKCE Implementation
Proof Key for Code Exchange (PKCE) is required for public clients. Confidential clients can omit it. If a client sends a code_challenge, it must use S256 and send the matching code_verifier when exchanging the code.
1. Generate Code Verifier and Challenge
// Generate a random code verifier (43-128 characters)
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64URLEncode(array);
}
// Create code challenge from verifier
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest("SHA-256", data);
return base64URLEncode(new Uint8Array(digest));
}
// Base64 URL encoding helper
function base64URLEncode(str) {
return btoa(String.fromCharCode.apply(null, str))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
2. Use in Authorization Request
Include code_challenge and code_challenge_method=S256 in your authorization URL.
3. Include in Token Exchange
Send the original code_verifier when exchanging the authorization code for tokens.
Error Handling
Authorization Errors
invalid_request- Missing or invalid parametersunauthorized_client- Client not authorized for this grant typeaccess_denied- User denied authorizationunsupported_response_type- Invalid response typeinvalid_scope- Requested scope is invalid or unknownserver_error- Internal server error
Token Errors
invalid_request- Missing or invalid parametersinvalid_client- Client authentication failedinvalid_grant- Authorization code/refresh token is invalid or expiredunauthorized_client- Client not authorized for this grant typeunsupported_grant_type- Grant type not supported
Best Practices
- Store tokens securely - Never expose tokens in client-side code
- Implement proper error handling - Handle token expiration gracefully
- Use HTTPS only - All OAuth flows must use secure connections
- Validate state parameter - Prevent CSRF attacks
- Request minimal scopes - Only request permissions you actually need
- Implement token refresh - Handle access token expiration automatically
Rate Limits
OAuth tokens are subject to the same rate limits as API keys. Monitor your usage and implement appropriate backoff strategies.
Next steps
- OAuth — how RevenueCat developers connect to your client and revoke access
- REST API v2 — the endpoints your access token can call
To register a client or ask about the integration, contact support@revenuecat.com.