---
title: Best Practices
url: https://docs.kaltura.com/docs/getting-started/authentication/ks-best-practices
---

## Best Practices

- **Use AppTokens in production.** Generate KS via `appToken.startSession` with HMAC — keep admin secrets off application servers (see [AppTokens Guide](/docs/getting-started/authentication/app-tokens-overview)).
- **Use USER KS (type=0) for client-side operations.** Reserve ADMIN KS (type=2) for server-side workflows that require write access.
- **Set short TTLs.** 1 hour for user-facing sessions, 15 minutes for server-side automation. Shorter sessions reduce exposure if a token leaks.
- **Scope privileges minimally.** Use `setrole`, `privacycontext`, `sview`, and `iprestrict` to limit what a KS can access.
- **Call `session.end` to revoke when done.** Use the `sessionid` privilege to enable bulk logout across devices.
- **Pass KS in POST bodies.** POST bodies keep tokens private — URL parameters appear in referrer headers, proxy logs, and browser history.

### Mobile / Client-Side KS Best Practices

Mobile and single-page apps require special care because compiled binaries and client-side JavaScript are accessible to end users:

- **Keep `adminSecret` on your backend server.** API secrets are permanent — use Application Tokens (AppTokens) for all scenarios requiring revocable credentials. See [AppTokens Guide](/docs/getting-started/authentication/app-tokens-overview).
- **Generate KS server-side and pass to the client per-session.** Issue fresh KS tokens per session to ensure continuous access and maintain full revocation control.
- **Three recommended strategies for client-side KS:**
  1. **Anonymous access** — Use `session.startWidgetSession` for public, unauthenticated content (player bootstrap, public galleries).
  2. **Server-generated KS** — Your backend generates a scoped USER KS (via `session.start` or `appToken.startSession`) and passes it to the client per-session. Secrets remain exclusively on the server.
  3. **User login** — Use `user.loginByLoginId` for apps where users authenticate with their own credentials. The KS is generated server-side and returned to the client.


### Entitlements & KS Privileges Patterns

#### Make the client KS playback-only

Lock KS to a minimal playback role: add `setrole:PLAYBACK_BASE_ROLE` so only a white-listed set of read/player calls is allowed (e.g., `baseEntry.get`, `flavorAsset.list`).

If your content is public and unauthenticated, you can use a Widget KS instead (anonymous, READ-only, for publicly available assets). For protected content, issue a USER KS with entitlements (see below).

#### Enforce entitlements with privacy context

If your catalog uses Entitlements, enable server-side checks on the KS and set the privacy context that scopes what the user can see:
* `enableentitlement` — tells Kaltura to enforce entitlement checks on this KS.
* `privacycontext:&lt;LABEL&gt;` — sets the entitlement partition (&lt;LABEL&gt; is free-text label you define in the KMC per category).

> Example: `enableentitlement,privacycontext:PORTAL_A` ensures results are scoped to the category membership of privacy context `PORTAL_A`. Use `enableentitlement` on all client-facing KS.

#### Scope what can be viewed or listed

*	Playback scope: Allow all playback in the entitlement context: `sview:*`. *Or* lock to a single entry: `sview:&lt;ENTRY_ID&gt;` (use with KS-restricted access control to ensure entries require authenticated access).
*	Listing across owners: `list:*` enables listing entries beyond the session's current user. Use only when your UX requires global search/browse.

#### Identify the user when you can

If your app requires authentication, set `userId` when you issue the KS. This ties server behavior and visibility to that user (e.g., lists are constrained for USER KS; ownership and visibility derive from the user in the KS, analytics are tied to the session' `userId`).

##### Analytics tracking

Specifying an app id (privilege: `appId:<APP_NAME-APP_DOMAIN>`) which contains the name and domain of the app allows you to get specific analytics per application, for cases where you're running your application across various domains.

#### Extra hardening knobs (use sparingly)

Add one or two of these when risk justifies it:

*	Action budget: `actionslimit:&lt;N&gt;` — cap how many API calls the KS can make.
*	IP lock: `iprestrict:<IPv4>` — restrict KS use to a single IP.
*	URI lock: `urirestrict:/api_v3/*` — restrict which API paths the KS can call.

> All three reduce blast radius if a KS leaks.
> NOTE: IP restriction works alongside CDN IP Tokenization, which requires a delivery profile configured on your account (one-time setup by your Kaltura account team).

#### App-specific scoping (generic pattern)

Some applications read app-specific hints from the KS to route or filter queries (for example, an application ID or category constraints). Keep these server-parsed and use unique namespaces for each application:
For example: `genieid:&lt;AI_GENIE_INSTANCE&gt;`, etc. These can be read and used by the app and Kaltura backend in various contexts.

> Kaltura platform enforces only its known privileges; your app can parse and honor the custom ones as needed.

#### Copy/paste privilege sets

* Authenticated playback (entitlements on): `setrole:PLAYBACK_BASE_ROLE,enableentitlement,privacycontext:PORTAL_A,sview:*`
* Single-item playback ticket: `setrole:PLAYBACK_BASE_ROLE,enableentitlement,privacycontext:PORTAL_A,sview:1_abcd1234,actionslimit:4`
* Hardened client KS (adds IP & URI restrictions): `setrole:PLAYBACK_BASE_ROLE,enableentitlement,privacycontext:PORTAL_A,sview:*,iprestrict:203.0.113.7,urirestrict:/api_v3/*`

(All examples assume a USER KS issued server-side and delivered to the client via POST body.)

> Use scoped privileges; reserve `disableentitlement` and broad write access for controlled backend ADMIN sessions.
> Issue ADMIN sessions server-side with short TTLs, and call `session.end` to revoke when done.

#### Bulk logout / revocation via sessionid privilege

Set `sessionid:&lt;GUID&gt;` on the KS privileges and keep that GUID on your backend. To revoke an entire cohort of sessions (e.g., logout user from all devices), call `session.end` on a KS that has the same `sessionid:&lt;GUID&gt;` and reissue sessions with a new GUID.

`sessionid` privilege essentially groups a set of KS's together. When `session.end` is called with a ks that has `sessionid=X`, all other KS's that have `sessionid=X` become invalid as well.

## Related Guides

- **[API Overview](/docs/getting-started/general/api-overview)** — API structure, first call, multirequest batching, error handling
- **[AppTokens API](/docs/getting-started/authentication/app-tokens-overview)** — Secure server-to-server auth without sharing admin secrets (HMAC-based KS generation)
- **[Upload & Ingestion](/docs/rich-media-cms-apis/content-management/upload-ingestion-overview)** — Upload content and manage entries (requires KS)
- **[Player Embed](/docs/embeddable-kaltura-products/kaltura-player/player-embed-overview)** — Embed the player with KS for access-controlled content
- **[Webhooks](/docs/rich-media-cms-apis/integration/webhooks)** — Event-driven HTTP callbacks and email notifications (requires KS)
- **[Analytics Reports](/docs/rich-media-cms-apis/analytics/analytics-overview)** — `appId` privilege tags analytics per-application
- **[Distribution](/docs/rich-media-cms-apis/integration/distribution)** — Admin KS required for distribution profile management
