|
1 | 1 | --- |
2 | 2 | title: Clients |
3 | | -description: Understand how to register and configure application Clients in Faable Auth for web, mobile, and machine-to-machine integrations. |
| 3 | +description: Register and configure OAuth Clients in Faable Auth for SPAs, mobile, server-side web apps and machine-to-machine services — callbacks, web origins, refresh token lifetimes, client authentication and Dynamic Client Registration. |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | # Clients |
7 | 7 |
|
8 | | -In Faable Auth, a **Client** represents an application that needs to authenticate users or request authorization to access APIs. Depending on what you are building, a Client could be a Single Page Application (React, Vue, Angular), a native mobile app (iOS, React Native), a server-side web application (Express, Next.js), or a backend machine-to-machine service. |
| 8 | +In Faable Auth, a **Client** represents an application that authenticates users or requests authorization to access APIs: a Single Page Application (React, Vue, Angular), a native mobile app, a server-side web application, or a backend machine-to-machine service. |
9 | 9 |
|
10 | | -Clients are the entities that initiate the OAuth2 and OpenID Connect flows. You register and manage all your clients directly from the [Faable Dashboard](https://dashboard.faable.com) |
| 10 | +Clients are what initiate the OAuth 2.0 and OpenID Connect flows. You manage them from the [Faable Dashboard](https://dashboard.faable.com), or create them programmatically with [Dynamic Client Registration](#dynamic-client-registration). |
11 | 11 |
|
12 | 12 | ## Creating a Client |
13 | 13 |
|
14 | | -To integrate your application with Faable Auth, the first step is always to register a new Client in the dashboard. When you create a client, Faable Auth generates critical credentials that your app will use to identify itself to the authorization server: |
| 14 | +Registering a client generates two credentials: |
15 | 15 |
|
16 | | -- **Client ID:** A public, unique identifier for your application. This is safe to expose in client-side code (like a React or Expo app) and is used to tell Faable Auth which application is requesting a login screen. |
17 | | -- **Client Secret:** A confidential string used to authenticate the identity of the application. _This must be kept secure and should never be exposed in public apps (like SPAs or mobile apps)._ It is primarily used by backend services to exchange authorization codes for tokens. |
| 16 | +- **Client ID** — a public, unique identifier. Safe to ship in client-side code (React, Expo); it tells Faable Auth which application is asking. |
| 17 | +- **Client Secret** — a confidential string that proves the application's identity. _Never expose it in a SPA, a mobile binary, or anything a user can read._ It belongs to backends only. |
18 | 18 |
|
19 | 19 | ## Types of Clients |
20 | 20 |
|
21 | | -When building with Faable Auth, the architecture of your application dictates how the Client should be configured and which OAuth2 flows it should use: |
| 21 | +Your architecture dictates the configuration and the flow: |
22 | 22 |
|
23 | | -- **Single Page Web Applications (SPAs):** For frontend apps running entirely in the browser. Since they cannot securely store a Client Secret, they must use the Authorization Code Flow with PKCE. |
24 | | -- **Native / Mobile Apps:** For mobile and desktop applications. Like SPAs, they cannot guarantee the secrecy of credentials and also rely on PKCE for secure authentication. |
25 | | -- **Regular Web Applications:** For traditional server-side applications (like Express MVC or Next.js server components). Because the code runs on a secure backend server, these clients can safely store and utilize a Client Secret during the authentication flow. |
26 | | -- **Machine to Machine (M2M):** For backend services or background workers that need to securely call APIs without any human user involvement. They typically use the Client Credentials flow. |
| 23 | +| Client type | Where the code runs | Secret? | Flow | |
| 24 | +| ---------------------- | ------------------------------------------------ | ------- | -------------------------------------------------------------- | |
| 25 | +| **Single Page App** | The browser (React, Vue, Angular) | ❌ | [Authorization Code + PKCE](oauth-flows/authorization-code.md) | |
| 26 | +| **Native / Mobile** | The user's device (iOS, Android, React Native) | ❌ | [Authorization Code + PKCE](oauth-flows/authorization-code.md) | |
| 27 | +| **Regular Web App** | Your server (Express, Next.js server components) | ✅ | [Authorization Code](oauth-flows/authorization-code.md) | |
| 28 | +| **Machine to Machine** | A backend service or worker, no human involved | ✅ | [Client Credentials](oauth-flows/client-credentials.md) | |
| 29 | +| **Device / TV / CLI** | An input-constrained device | ❌ | [Device Code](oauth-flows/device-code.md) | |
| 30 | + |
| 31 | +Faable Auth enforces **PKCE with `S256`** — it advertises no other code challenge method — so public clients are covered whether or not a secret is present. |
27 | 32 |
|
28 | 33 | ## Client Configuration |
29 | 34 |
|
30 | | -Within the dashboard, you can define essential security boundaries for each Client: |
| 35 | +### Security boundaries |
31 | 36 |
|
32 | | -- **Allowed Callback URLs (Redirect URIs):** A strict whitelist of URLs (e.g., `https://myapp.com/callback`) where Faable Auth is permitted to redirect the user after a successful login. This is a critical security measure to prevent open redirect vulnerabilities. |
33 | | -- **Allowed Logout URLs:** URLs where users can be redirected after they successfully log out of their session. |
34 | | -- **Allowed Web Origins:** Origins (`scheme://host[:port]`, no path — e.g. `http://localhost:5173`) permitted to make cross-origin (CORS) requests to the token and passwordless endpoints for this client. **When the list is empty, any origin is allowed** — set it to lock browser calls down to your app's origins. The account's own auth domain (where the hosted login page lives) is always allowed implicitly, so you only need to list your application origins. |
35 | | -- **Connections:** You have granular control over which authentication methods (e.g., Google login, Passwordless) are enabled for each specific client. |
| 37 | +- **Allowed Callback URLs (`callbacks`)** — the whitelist of URLs Faable Auth may redirect to after login (e.g. `https://myapp.com/callback`). Prevents open-redirect abuse. |
| 38 | +- **Allowed Logout URLs (`logout_urls`)** — where users may be sent after [RP-Initiated Logout](oidc/logout.md). |
| 39 | +- **Allowed Web Origins (`web_origins`)** — origins (`scheme://host[:port]`, **no path** — e.g. `http://localhost:5173`) permitted to make cross-origin calls to the token and passwordless endpoints. **When the list is empty, any origin is allowed**; fill it in to lock browser calls down to your own app. Your account's auth domain is always allowed implicitly, so you only list your application origins. |
| 40 | +- **Connections** — which authentication methods (Google, passwordless, database…) this specific client may use. Set on each [connection](connections.md) via its _Enabled clients_ list. |
36 | 41 |
|
37 | | -## Next Steps |
| 42 | +### Token lifetimes |
| 43 | + |
| 44 | +| Setting | Effect | |
| 45 | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | |
| 46 | +| `refresh_token.token_lifetime` | Lifetime of issued refresh tokens, in seconds. **Default 2592000** (30 days). | |
| 47 | +| Access token lifetime | Not a client setting — it comes from the [API](apis.md) the token is issued for (`token_lifetime`), defaulting to 24 hours. | |
| 48 | + |
| 49 | +> `refresh_token.expiration_mode` and `refresh_token.infinite_token_lifetime` exist on the client object for Auth0 compatibility, but are **not enforced today** — only `token_lifetime` governs how long a refresh token lives. Don't rely on them to build a never-expiring session. |
| 50 | +
|
| 51 | +### Client authentication at the token endpoint |
| 52 | + |
| 53 | +`POST /oauth/token` accepts three methods, as published in your tenant's [discovery document](oidc): |
| 54 | + |
| 55 | +| `token_endpoint_auth_method` | How the client authenticates | For | |
| 56 | +| ---------------------------- | -------------------------------------------------------------- | ----------------------------- | |
| 57 | +| `client_secret_basic` | HTTP Basic header with `client_id:client_secret` (the default) | Confidential clients | |
| 58 | +| `client_secret_post` | `client_id` + `client_secret` in the form body | Confidential clients | |
| 59 | +| `none` | No secret — the PKCE `code_verifier` is the proof | Public SPA and native clients | |
| 60 | + |
| 61 | +### Application metadata |
| 62 | + |
| 63 | +Optional fields, mostly consumed by consent screens and by tooling: `client_uri`, `logo_uri`, `tos_uri`, `policy_uri`, `contacts`, `application_type` (`web` | `native`), `software_id`, `software_version`. |
| 64 | + |
| 65 | +### Front-Channel Logout |
38 | 66 |
|
39 | | -Once you have your Client ID and configured your callback URLs, you are ready to write code. |
| 67 | +A client may register a `frontchannel_logout_uri`: Faable loads it in a hidden iframe when the user logs out of the OP, so your application can clear its own session. Set `frontchannel_logout_session_required` to `true` and Faable includes `iss` and `sid` on that call, letting you scope the cleanup to the exact session. See [Logout](oidc/logout.md). |
| 68 | + |
| 69 | +## Dynamic Client Registration |
| 70 | + |
| 71 | +Clients can be created over HTTP instead of through the dashboard, per [OIDC Dynamic Client Registration 1.0 / RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591). This is what lets a third-party tool onboard itself against your tenant — MCP clients, IDE integrations and OAuth debuggers commonly expect it. |
| 72 | + |
| 73 | +The endpoint is published in your discovery document as `registration_endpoint`: |
| 74 | + |
| 75 | +```bash |
| 76 | +curl -X POST 'https://your-domain.auth.faable.link/oidc/register' \ |
| 77 | + -H 'content-type: application/json' \ |
| 78 | + -d '{ |
| 79 | + "client_name": "My Tool", |
| 80 | + "redirect_uris": ["https://tool.example.com/callback"], |
| 81 | + "grant_types": ["authorization_code", "refresh_token"], |
| 82 | + "response_types": ["code"], |
| 83 | + "token_endpoint_auth_method": "client_secret_basic" |
| 84 | + }' |
| 85 | +``` |
| 86 | + |
| 87 | +Response (`201`), per RFC 7591 §3.2.1 — this is the only time the secret is returned: |
| 88 | + |
| 89 | +```json |
| 90 | +{ |
| 91 | + "client_id": "…", |
| 92 | + "client_secret": "…", |
| 93 | + "client_id_issued_at": 1751641200, |
| 94 | + "client_secret_expires_at": 0, |
| 95 | + "redirect_uris": ["https://tool.example.com/callback"], |
| 96 | + "client_name": "My Tool", |
| 97 | + "grant_types": ["authorization_code", "refresh_token"], |
| 98 | + "response_types": ["code"], |
| 99 | + "token_endpoint_auth_method": "client_secret_basic", |
| 100 | + "application_type": "web" |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +Notes on behaviour: |
| 105 | + |
| 106 | +- **`redirect_uris` is the only required field.** Everything else defaults per spec: `grant_types` to `["authorization_code"]`, `response_types` to `["code"]`, `token_endpoint_auth_method` to `client_secret_basic`, `application_type` to `web`. |
| 107 | +- **Unsupported metadata is rejected**, not silently accepted. Requesting a grant type Faable doesn't implement returns `400`. Supported grants are `authorization_code`, `refresh_token`, `client_credentials`, `urn:ietf:params:oauth:grant-type:device_code`, `urn:ietf:params:oauth:grant-type:token-exchange` and Auth0's passwordless OTP grant. |
| 108 | +- **`client_secret_expires_at` is `0`** — issued secrets don't expire. |
| 109 | +- **The client is bound to the tenant resolved from the request host**, so register against the domain you actually want it to live in. |
| 110 | +- **`web_origins`** is accepted as a non-standard extra, with the same rules as in the dashboard. |
| 111 | +- **Registration is not itself authenticated.** Anyone who can reach your auth domain can create a client in your tenant — a new client grants no access on its own, but if that's not a trade-off you want, keep an eye on `oauth.client.register` entries in your [logs](logs.md). |
| 112 | + |
| 113 | +## Next Steps |
40 | 114 |
|
41 | | -- **[Connections](connections.md):** Learn more about the different identity providers you can attach to your clients. |
42 | | -- **[Authorization Code Flow](oauth-flows/authorization-code.md):** Understand the mechanics of the standard login flow. |
43 | | -- **[Quickstart Next.js](quickstart/nextjs.md):** Jump straight into the code and see a full authentication implementation in action. |
44 | | -- **[Quickstart React Native](quickstart/react-native.md):** Jump straight into the code and see a full authentication implementation in action. |
| 115 | +- **[Connections](connections.md)** — the identity providers you attach to a client. |
| 116 | +- **[Authorization Code Flow](oauth-flows/authorization-code.md)** — the mechanics of the standard login flow. |
| 117 | +- **[APIs](apis.md)** — register the resource servers your clients request tokens for. |
| 118 | +- **[Quickstarts](quickstart/nextjs.md)** — jump into working code, including [FastAPI](quickstart/fastapi.md) on the backend side. |
0 commit comments