Skip to main content

Manual Authentication for Content APIs

Use this page when you are not using the JS/TS SDK and need to request Content API tokens manually from your backend.

What this page covers

Credentials, environment URLs, the exact token request, a sample token response, and the server-only rule for Content APIs.

Credentials and Environment Variables​

These manual examples use the following environment variables:

VariableRequiredDescription
QF_CLIENT_IDYesYour Quran Foundation client ID.
QF_CLIENT_SECRETYesYour Quran Foundation client secret. Store it on the server only.
QF_ENVNoprelive or production. Default to prelive for development and testing.

If your project already uses QURAN_CLIENT_ID and QURAN_CLIENT_SECRET, that is fine. Keep one naming scheme consistent throughout your codebase.

Environment URLs​

EnvironmentAuth URLAPI base URL
prelivehttps://prelive-oauth2.quran.foundationhttps://apis-prelive.quran.foundation
productionhttps://oauth2.quran.foundationhttps://apis.quran.foundation

The token is environment-specific. A prelive token will not work against production APIs, and a production token will not work against prelive APIs.

Token Request​

Request the access token from your backend with OAuth2 Client Credentials.

Request details:

  • Method: POST
  • URL: {authBaseUrl}/oauth2/token
  • Auth: HTTP Basic with client_id:client_secret
  • Content-Type: application/x-www-form-urlencoded
  • Body: grant_type=client_credentials&scope=content
curl --request POST \
--url https://prelive-oauth2.quran.foundation/oauth2/token \
--user 'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'grant_type=client_credentials&scope=content'
Expand for Python and Node.js token request examples

Python Example (requests)​

import os

import requests
from requests.auth import HTTPBasicAuth

AUTH_BASE_BY_ENV = {
"prelive": "https://prelive-oauth2.quran.foundation",
"production": "https://oauth2.quran.foundation",
}

env = os.getenv("QF_ENV", "prelive")
if env not in AUTH_BASE_BY_ENV:
raise ValueError(
f"Invalid QF_ENV value: {env!r}. Expected 'prelive' or 'production'."
)

AUTH_BASE_URL = AUTH_BASE_BY_ENV[env]

response = requests.post(
f"{AUTH_BASE_URL}/oauth2/token",
auth=HTTPBasicAuth(
os.environ["QF_CLIENT_ID"],
os.environ["QF_CLIENT_SECRET"],
),
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={
"grant_type": "client_credentials",
"scope": "content",
},
timeout=30,
)
response.raise_for_status()

token = response.json()
access_token = token["access_token"]
expires_in = token["expires_in"]

Node.js Example (fetch)​

This example assumes Node 18+ or another runtime with a global fetch implementation.

async function getToken() {
const authBaseByEnv = {
production: "https://oauth2.quran.foundation",
prelive: "https://prelive-oauth2.quran.foundation",
};
const env = process.env.QF_ENV ?? "prelive";
if (!(env in authBaseByEnv)) {
throw new Error("QF_ENV must be 'prelive' or 'production'");
}

const authBaseUrl = authBaseByEnv[env];

const basicAuth = Buffer.from(
`${process.env.QF_CLIENT_ID}:${process.env.QF_CLIENT_SECRET}`,
).toString("base64");

const response = await fetch(`${authBaseUrl}/oauth2/token`, {
method: "POST",
headers: {
Authorization: `Basic ${basicAuth}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "client_credentials",
scope: "content",
}),
});

if (!response.ok) {
throw new Error(`Token request failed: ${response.status}`);
}

return response.json();
}

getToken()
.then(({ expires_in }) => {
console.log("Fetched token that expires in", expires_in, "seconds");
})
.catch((error) => {
console.error("Token request failed:", error);
});

Sample Token Response​

{
"access_token": "YOUR_ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 3600,
"scope": "content"
}

Track access_token and expires_in. Client Credentials does not return a refresh token for this quickstart flow.

Server-Only Rule​

Do not call the token endpoint from browser or mobile code. The request requires client_secret, and exposing that secret breaks the security model of the integration.

Recommended pattern:

  1. Request the token on your backend.
  2. Cache it in memory or your server-side cache.
  3. Use the token when your backend calls the Content APIs.
  4. Return only the API data your frontend needs.

AI Handoff Prompt​

Use this prompt when you want an AI coding tool to implement manual token retrieval on your backend:

Expand AI handoff prompt
Implement Quran Foundation Content API token retrieval on the backend.

Requirements
- Read QF_CLIENT_ID, QF_CLIENT_SECRET, and QF_ENV from environment variables.
- Use prelive -> https://prelive-oauth2.quran.foundation and production -> https://oauth2.quran.foundation.
- Request POST /oauth2/token with HTTP Basic auth, grant_type=client_credentials, and scope=content.
- Return access_token and expires_in from the token response.
- Do not expose client_secret to browser or mobile code.

Documentation to follow
- Manual authentication: https://api-docs.quran.foundation/docs/quickstart/manual-authentication
- Token management: https://api-docs.quran.foundation/docs/quickstart/token-management

Continue the Manual Flow​