# Register an app

> Self-service OAuth client registration in Settings → Team → OAuth apps: public vs confidential clients, the redirect-URI rules, post-logout URIs, scopes, and the one-time client secret.

Before an app can sign users in, it needs a **client** — a registration that tells EntryBit its name, its allowed redirect URIs, and the scopes it may request. Registration is **self-service**: any org admin can create a client in **Settings → Team → OAuth apps**, no support ticket required.

Clients are strictly **tenant-scoped**: a client is created under your organization, and only your organization can list, view, or delete it. Self-registered clients are marked **unverified** — the consent screen flags them as third-party apps. Each organization can have up to **50 active clients**.

## Public vs confidential

Choose the client type by whether the app can keep a secret:

| | Public | Confidential |
|---|---|---|
| For | Mobile apps, SPAs | Web apps with a secure backend |
| Client secret | **None** | Issued **once** at creation |
| Proof of identity | PKCE only | PKCE **+** `client_secret` |
| Can introspect tokens | No | Yes ([Introspection](/docs/oauth/introspection-revocation/)) |

**PKCE (S256) is required for both.** A public client is safe without a secret because PKCE binds each authorization code to a per-request verifier only the app holds. A confidential client adds a secret on top, which unlocks token introspection.

> Not sure which? A phone app or a browser-only SPA **cannot** keep a secret — register it as **public**. Only register **confidential** if the credential lives on a server you control.

## Registration fields

In **Settings → Team → OAuth apps → Register**, provide:

| Field | Required | Notes |
|---|---|---|
| `client_name` | ✓ | Shown on the consent screen. |
| `client_type` | ✓ | `public` or `confidential`. |
| `redirect_uris` | ✓ | One or more exact callback URIs (see rules below). |
| `post_logout_redirect_uris` |  | Where the browser may land after [logout](/docs/oauth/logout/). |
| `scopes` |  | The scopes this client may request (see [Scopes](/docs/oauth/scopes/)). |
| `logo_uri` |  | Displayed on the consent screen. |
| `client_uri` |  | Your app's homepage, linked from consent. |

On success you receive a `client_id`. For a **confidential** client you also receive a `client_secret` **exactly once** — store it immediately (it is SHA-256 hashed server-side and can never be retrieved again).

```json
{
  "success": true,
  "client_id": "eb_9f1c2ab34cd56ef7",
  "client_secret": null,
  "client_type": "public",
  "token_endpoint_auth_method": "none",
  "redirect_uris": ["entrybitresident://oauth/callback"],
  "allowed_scopes": "openid profile email offline_access passes:read"
}
```

> **`client_id` is public.** It ships in your app config and appears in every authorize request — that is by design. Only a confidential client's `client_secret` is sensitive. See [Authentication](/docs/get-started/authentication/) for the `client_id` vs `eb_sk_…` distinction.

## Redirect-URI rules

The redirect URI is where the browser hands the authorization code back to your app. EntryBit matches it **byte-for-byte** against your registered list — this is the open-redirect guard, so the rules are strict:

- **Exact match, no wildcards.** The request's `redirect_uri` must equal a registered one character-for-character.
- **No fragments.** A `#…` fragment is rejected.
- **Absolute URIs only.**
- **Web:** `https` is required (`http://localhost` is allowed for development).
- **Native:** a custom scheme such as `entrybitresident://oauth/callback` is allowed. A custom scheme is not OS-guaranteed unique — **PKCE is what protects you**: a hostile app that registers the same scheme still cannot exchange the intercepted code without your `code_verifier`. For the strongest binding, use a claimed `https` deep link (iOS Universal Link / Android App Link) if you can host the domain-association files.

`post_logout_redirect_uris` follow the same exact-match rules and are kept in a **separate list** from login redirect URIs.

## After registration

- Ship the `client_id` in your app and follow the [OAuth flow](/docs/oauth/overview/) (or the [React Native quickstart](/docs/get-started/quickstart-react-native/)).
- Users can see and revoke your app anytime under **Settings → Connected apps**; revoking there drops the stored consent and every refresh token the app holds for that user.
- To retire a client, delete it in **Settings → Team → OAuth apps** — it deactivates immediately and frees a slot against the 50-client cap.

Registering an app is different from minting an [API key](/docs/api-keys/overview/) (**Settings → API keys**): a client signs *users* in; an API key acts as the *organization*.