Skip to content

Commit f94f071

Browse files
authored
Document backend proxy guidance for web User API calls (#130)
* docs: clarify user api browser origin requirements * docs: recommend backend proxy for web user apis * docs: tighten web proxy guidance wording
1 parent 80a0c76 commit f94f071

4 files changed

Lines changed: 34 additions & 3 deletions

File tree

‎docs/tutorials/faq.mdx‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ Submit an [application](/request-access) to receive your `client_id` and `client
2626

2727
Include your OAuth2 access token in the `x-auth-token` header and your client ID in the `x-client-id` header when calling authenticated endpoints.
2828

29+
For web apps, the recommended pattern is to store the user session in your backend or secure `httpOnly` cookies and have your backend or serverless proxy send `x-auth-token` and `x-client-id` to Quran Foundation.
30+
31+
## Why does the same request work in curl but fail in the browser?
32+
33+
`curl` usually sends no browser `Origin` header, while browser JavaScript does. If you call a User API directly from page code on a third-party origin, the request can be rejected by the target service's browser-origin policy even when the token itself is valid.
34+
35+
For confidential web integrations, route the resource request through your backend or serverless proxy instead of calling Quran Foundation directly from the page.
36+
2937
## What are the best practices for refresh tokens?
3038

3139
Store refresh tokens securely and reuse them until they expire. Refresh tokens allow you to obtain new access tokens without asking the user to re-authorize.

‎docs/tutorials/oidc/example-integration.mdx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ const response = await fetch(
7676
const bookmarks = await response.json();
7777
```
7878

79+
This example keeps the user session on the server and uses the server to send `x-auth-token` and `x-client-id` to Quran Foundation. That is the recommended pattern for confidential web clients. If you move the resource call into frontend browser code, you leave that server-side pattern and may run into browser-origin restrictions.
80+
7981
## Accessing Resources
8082

8183
Once authenticated, explore the [User APIs](/docs/category/user-related-apis):

‎docs/tutorials/oidc/getting-started-with-oauth2.mdx‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,10 @@ sequenceDiagram
232232
Auth-->>Backend: Token Response<br/>(access_token, refresh_token)
233233
Backend-->>App: Session or token payload
234234
235-
App->>API: Use token to call Quran.Foundation's API
236-
API-->>App: Requested resource
235+
App->>Backend: Request resource
236+
Backend->>API: Use token to call Quran.Foundation's API
237+
API-->>Backend: Requested resource
238+
Backend-->>App: Requested resource
237239
238240
Note over App,Backend: Access token expires (1 hour)
239241
@@ -757,6 +759,8 @@ x-client-id: YOUR_CLIENT_ID
757759

758760
Note: the collections examples below require the `collection` scope, and other User API endpoints may require additional scopes such as `user`. A token granted only `openid offline_access` is sufficient for login and refresh, but not for every User API call.
759761

762+
For confidential web clients, the recommended pattern is to have your backend or serverless proxy send these headers on outbound requests to Quran Foundation. Your app can keep the user session in a server session or secure `httpOnly` cookies while the backend injects `x-auth-token` and `x-client-id`.
763+
760764
<details>
761765
<summary><b>cURL — Get collections</b></summary>
762766

@@ -822,6 +826,8 @@ Implementation requirements (server-side)
822826
- Build a client wrapper that automatically:
823827
- injects x-auth-token and x-client-id on every request
824828
- targets the correct API base URL from getQfOAuthConfig()
829+
- For web apps, prefer making the resource call from your backend or proxy layer rather than from page JavaScript.
830+
- If you intentionally make the resource call from browser code, the browser origin must still be accepted by the target service.
825831
826832
User API base
827833
- Use apiBaseUrl from config:
@@ -1007,6 +1013,7 @@ Acceptance checklist
10071013
- Scopes: Use `openid offline_access user collection`. Add more scopes only as needed.
10081014
- Scopes note: Quran.Foundation expects `offline_access` (not `offline`).
10091015
- Token storage: Store `refresh_token` securely; rotate if compromised.
1016+
- Browser-origin policy: Direct browser calls to User APIs require the calling origin to be allowlisted by the target service. If your origin is not allowlisted, call the API from your backend instead.
10101017
- Clock skew: Ensure system time is correct (e.g., via NTP) to avoid `invalid_grant` due to time drift.
10111018

10121019
> Do not mix tokens across environments. A token from Pre-Production will not work on Production, and vice versa.
@@ -1054,6 +1061,7 @@ Acceptance checklist
10541061
| `redirect_uri_mismatch` | Redirect URI not exact match | Align with registered value |
10551062
| `invalid_scope` | Scope misspelled or not allowed | Use valid scopes; request incrementally |
10561063
| `401 Unauthorized` (APIs) | Missing/expired token | Send `x-auth-token` and `x-client-id`, refresh token |
1064+
| `403 Forbidden` (APIs) | Direct browser call from a restricted origin, or scope/permission is not granted | For web apps, route the request through your backend or proxy; otherwise use a supported browser origin and request the correct scope |
10571065

10581066
<details>
10591067
<summary><b>AI prompt: troubleshooting + safe logs</b></summary>
@@ -1071,6 +1079,8 @@ User API errors
10711079
- 401: missing/expired token:
10721080
- refresh once (if refresh_token exists), retry once
10731081
- if still failing, require re-auth (do not loop)
1082+
- 403: browser origin not allowlisted:
1083+
- move the resource call to your backend, or use an origin the target service allows
10741084
- 403: scope/permission not granted:
10751085
- hide/disable feature and prompt user for correct consent
10761086
@@ -1131,7 +1141,7 @@ x-auth-token: YOUR_ACCESS_TOKEN
11311141
x-client-id: YOUR_CLIENT_ID
11321142
```
11331143

1134-
See [Step 4: Call User APIs with Headers](#step-4-call-user-apis-with-headers) for complete examples in cURL, JavaScript, and Python.
1144+
For web apps, your backend or serverless proxy should usually be the component that sends these headers to Quran Foundation. See [Step 4: Call User APIs with Headers](#step-4-call-user-apis-with-headers) for complete examples in cURL, JavaScript, and Python.
11351145

11361146
### I'm getting `invalid_client` — what's wrong?
11371147

‎docs/tutorials/oidc/user-apis-quickstart.mdx‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ Quran Foundation User APIs use OAuth2 Authorization Code flow with PKCE and Open
3636

3737
This pattern gives you OAuth2 and OpenID Connect without embedding secrets in a mobile app or browser app. It also keeps the integration aligned with how most Request Access clients are provisioned today.
3838

39+
For web apps, the recommended shape is:
40+
41+
- keep token exchange and refresh on your backend
42+
- keep the app's user session in secure server storage or `httpOnly` cookies
43+
- have your backend or serverless proxy send `x-auth-token` and `x-client-id` when calling Quran Foundation User APIs
44+
45+
Direct browser calls from third-party origins are not the recommended web pattern and may be rejected by CORS allowlisting or other origin allowlist checks.
46+
3947
## Choose Your Platform
4048

4149
Use the quickstart guidance on this page for the architecture decision, then jump to the guide that matches your stack.
@@ -87,6 +95,8 @@ const response = await fetch(
8795
const bookmarks = await response.json();
8896
```
8997

98+
For web apps, this request is typically made by your backend or serverless proxy, not by page JavaScript. Cookies are for your app's own session; `x-auth-token` and `x-client-id` are the headers your server sends to Quran Foundation.
99+
90100
## Quick Reference
91101

92102
### Common scopes
@@ -120,6 +130,7 @@ Request only the scopes your app actually needs.
120130
- Mixing prelive and production OAuth2 environments.
121131
- Requesting more scopes than your app needs.
122132
- Treating the `id_token` as an API access token instead of using the `access_token`.
133+
- Calling User APIs directly from browser JavaScript in a confidential web integration instead of routing the request through your backend or proxy.
123134

124135
## AI Handoff Prompt
125136

0 commit comments

Comments
 (0)