Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

1 change: 0 additions & 1 deletion docs/content_apis_versioned/4.0.0/hadiths-by-ayah.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

1 change: 0 additions & 1 deletion docs/content_apis_versioned/hadiths-by-ayah.api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,3 @@ Service Unavailable
Gateway Timeout

</div><div><MimeTabs schemaType={"response"}><TabItem label={"application/json"} value={"application/json"}><SchemaTabs><TabItem label={"Schema"} value={"Schema"}><details style={{}} data-collapsed={false} open={true}><summary style={{"textAlign":"left"}}><strong>Schema</strong></summary><div style={{"textAlign":"left","marginLeft":"1rem"}}></div><ul style={{"marginLeft":"1rem"}}><SchemaItem collapsible={false} name={"message"} required={false} schemaName={"string"} qualifierMessage={undefined} schema={{"type":"string"}}></SchemaItem><SchemaItem collapsible={false} name={"type"} required={false} schemaName={"string"} qualifierMessage={"**Possible values:** [`gateway_timeout`, `service_unavailable`, `bad_gateway`, `internal_server_error`, `unprocessable_entity`, `not_found`, `forbidden`, `unauthorized`, `invalid_request`, `invalid_token`, `insufficient_scope`, `service_error`, `invalid_path`, `rate_limit_exceeded`]"} schema={{"type":"string","enum":["gateway_timeout","service_unavailable","bad_gateway","internal_server_error","unprocessable_entity","not_found","forbidden","unauthorized","invalid_request","invalid_token","insufficient_scope","service_error","invalid_path","rate_limit_exceeded"]}}></SchemaItem><SchemaItem collapsible={false} name={"success"} required={false} schemaName={"boolean"} qualifierMessage={undefined} schema={{"type":"boolean"}}></SchemaItem></ul></details></TabItem><TabItem label={"Example (from schema)"} value={"Example (from schema)"}><ResponseSamples responseExample={"{\n \"message\": \"string\",\n \"type\": \"gateway_timeout\",\n \"success\": true\n}"} language={"json"}></ResponseSamples></TabItem><TabItem label={"Example"} value={"Example"}><ResponseSamples responseExample={"{\n \"message\": \"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server\",\n \"type\": \"gateway_timeout\",\n \"success\": false\n}"} language={"json"}></ResponseSamples></TabItem></SchemaTabs></TabItem></MimeTabs></div></TabItem></ApiTabs></div>

13 changes: 12 additions & 1 deletion docs/tutorials/oidc/user-apis-quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ sidebar_label: "User APIs Quickstart"

Quran Foundation User APIs use OAuth2 Authorization Code flow with PKCE and OpenID Connect. For most newly issued Request Access clients, the safest default is a confidential-client setup: your app handles the login redirect, but your backend keeps `CLIENT_SECRET` and exchanges the code for tokens.

## Production vs Pre-live

:::warning Pre-live uses a separate user stack
If you are testing User APIs in pre-live, keep the entire flow in pre-live.

- Use the [Pre-live User-related APIs reference](/docs/user_related_apis_prelive/user-related-apis) when testing pre-live endpoints.
- Use [prelive.quran.com](https://prelive.quran.com) for auth paths and auth-backed user data checks.
- Use [prelive.quranreflect.org](https://prelive.quranreflect.org) for Quran Reflect paths and data checks.
- Do not mix production login state, production user data, or production docs with pre-live testing.
:::

## Recommended Architecture

:::important Default integration shape
Expand Down Expand Up @@ -127,7 +138,7 @@ Request only the scopes your app actually needs.
- Embedding `CLIENT_SECRET` in a mobile app or browser app.
- Calling `/oauth2/token` directly from a confidential client without backend client authentication.
- Skipping OAuth2 `state` validation, or `nonce` validation when you rely on `id_token`.
- Mixing prelive and production OAuth2 environments.
- Mixing pre-live and production OAuth2 environments, sessions, or manual test surfaces.
- Requesting more scopes than your app needs.
- Treating the `id_token` as an API access token instead of using the `access_token`.
- Calling User APIs directly from browser JavaScript in a confidential web integration instead of routing the request through your backend or proxy.
Expand Down
58 changes: 55 additions & 3 deletions src/components/UserRelatedApiEnvironmentNotice/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,65 @@ const getCopy = (environment: "production" | "pre-live") => {
if (environment === "pre-live") {
return {
title: "Pre-live user-related API docs",
body: "",
body: (
<>
<p>
These pages describe the Pre-live user-related API stack.
</p>
<p>
Use pre-live OAuth credentials, pre-live API base URLs, and
pre-live app URLs when following this documentation. Keep your
OAuth flow, API requests, callback URLs, and manual testing within
the pre-live environment.
</p>
<ul className={styles.list}>
<li>
Use{" "}
<a
href="https://prelive.quran.com"
target="_blank"
rel="noreferrer"
>
prelive.quran.com
</a>{" "}
for auth-related testing.
</li>
<li>
Use{" "}
<a
href="https://prelive.quranreflect.org"
target="_blank"
rel="noreferrer"
>
prelive.quranreflect.org
</a>{" "}
for Quran Reflect paths where applicable.
</li>
<li>
Do not mix production sessions or production user data with
pre-live testing.
</li>
</ul>
</>
),
};
}

return {
title: "Production user-related API docs",
body: "",
body: (
<>
<p>These pages describe the Production user-related API stack.</p>
<p>
Use production OAuth credentials, production API base URLs, and
production app URLs when following this documentation.
</p>
<p>
Need to test before going live? Switch to the Pre-live docs using the
environment switcher above.
</p>
</>
),
};
};

Expand Down Expand Up @@ -108,7 +160,7 @@ export default function UserRelatedApiEnvironmentNotice({
})}
</nav>
</div>
<p className={styles.body}>{copy.body}</p>
<div className={styles.body}>{copy.body}</div>
</div>
);
}
13 changes: 10 additions & 3 deletions src/components/UserRelatedApiEnvironmentNotice/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const PROD_CATEGORY_PATH = '/docs/category/user-related-apis';
const PRELIVE_CATEGORY_PATH = '/docs/category/user-related-apis-pre-live';
const PROD_LATEST_ROOT = '/docs/user_related_apis_versioned';
const PRELIVE_ROOT = '/docs/user_related_apis_prelive';
const PROD_INTRO_PATH = `${PROD_LATEST_ROOT}/user-related-apis`;
const PRELIVE_INTRO_PATH = `${PRELIVE_ROOT}/user-related-apis`;
const PROD_LATEST_PREFIX = `${PROD_LATEST_ROOT}/`;
const PRELIVE_PREFIX = `${PRELIVE_ROOT}/`;
const PROD_VERSION_PREFIX_REGEX = /^\d+\.\d+\.\d+(\/|$)/;
Expand All @@ -12,6 +14,8 @@ const isPathInTree = (pathname, rootPath) =>
pathname === rootPath || pathname.startsWith(`${rootPath}/`);
const isApiTreeRoot = (pathname) =>
pathname === PROD_LATEST_ROOT || pathname === PRELIVE_ROOT;
const isCategoryPath = (pathname) =>
pathname === PROD_CATEGORY_PATH || pathname === PRELIVE_CATEGORY_PATH;
const hasAvailablePath = (availablePaths, targetPath) => {
const normalizedTargetPath = normalizePath(targetPath);

Expand All @@ -22,7 +26,7 @@ const hasAvailablePath = (availablePaths, targetPath) => {
};
const stripPrefix = (value, prefix) => value.slice(prefix.length);
const getFallbackPath = (environment) =>
environment === 'production' ? PROD_CATEGORY_PATH : PRELIVE_CATEGORY_PATH;
environment === 'production' ? PROD_INTRO_PATH : PRELIVE_INTRO_PATH;
Comment thread
basit3407 marked this conversation as resolved.

function getUserRelatedDocsAvailablePaths(allDocsData) {
const paths = new Set();
Expand Down Expand Up @@ -111,8 +115,11 @@ function getTargetPath(pathname, targetEnvironment) {

function getUserRelatedDocsTarget(pathname, targetEnvironment, options = {}) {
const { fallbackPath, targetPath } = getTargetPath(pathname, targetEnvironment);
const hasExplicitDocTarget = targetPath !== fallbackPath && !isApiTreeRoot(targetPath);
const hasEquivalentDoc = !hasExplicitDocTarget || !options.availablePaths
const needsAvailableDoc =
targetPath !== fallbackPath &&
!isApiTreeRoot(targetPath) &&
!isCategoryPath(targetPath);
const hasEquivalentDoc = !needsAvailableDoc || !options.availablePaths
? true
: hasAvailablePath(options.availablePaths, targetPath);
const path = hasEquivalentDoc ? targetPath : fallbackPath;
Expand Down
21 changes: 21 additions & 0 deletions src/components/UserRelatedApiEnvironmentNotice/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,27 @@
color: var(--ifm-color-emphasis-800);
}

.body p {
margin: 0;
}

.body > * + * {
margin-top: 0.75rem;
}

.body a {
font-weight: 600;
}

.list {
margin: 0;
padding-left: 1.25rem;
}

.list li + li {
margin-top: 0.35rem;
}

.switcher {
display: inline-flex;
align-items: center;
Expand Down
Loading