# SDKs and Application Integration

From [Descope Fundamentals](https://learn.descope.io/c/foundations) — Learn the platform by configuring your own project — every module ends in work the app checks for real.

Take this course interactively at https://learn.descope.io/c/foundations/sdks-and-integration

---

![Backend SDK Integration. 3 minutes.](video:sdks-and-integration-backend-sdk-integration)

Where the client SDK holds a user's tokens, the backend SDK decides whether a request may proceed. Descope ships backend SDKs for Node.js, Python, Go, Java, Ruby, PHP, and .NET, and regardless of language the core call is the same: extract the session token from the Authorization header or cookie and pass it to validateSession.

Validation is offline by default. The SDK fetches Descope's public signing keys (JWKS) once and caches them, so most calls verify the signature locally with no network round trip — on a high-traffic service you can safely extend that cache, since the SDK re-fetches automatically if it ever sees a token signed by an unfamiliar key. You can also validate against a specific audience, or a list of them, so a token minted for one purpose cannot be replayed against a service it was never intended for. If a server has no outbound internet access at all, skip JWKS fetching entirely by providing a custom public key at initialization.

When validation fails the SDK raises an exception: catch it and return a 401. Several SDKs also expose a combined validate-and-refresh call, so an expired session token is transparently refreshed using the accompanying refresh token in a single step rather than a separate round trip.

The Management SDK is a different tool for a different job. Where session validation checks one user's token, the Management SDK requires a management key — generated under Company → Management Keys — and lets your backend act on behalf of the whole project: changing custom claims on an existing JWT, extending how long an updated token stays valid, or minting a full Descope session for a user programmatically, independent of any authentication method. That last capability is what makes backend-driven migrations possible, and what lets automated tests generate valid tokens.

> [!WARNING]
> A management key is not a session token. It authorizes your backend to act project-wide, including minting sessions for arbitrary users, so these calls must only run in trusted server-side code — and the key must never reach a client, a log file, or a frontend build.

## Key terms

- Management key — a project-wide credential, distinct from a session token, for backend-driven operations.
- JWT authorizer — a gateway or reverse-proxy feature validating a Descope JWT before a request reaches your backend.

## Summary

- Why validateSession rarely costs a network call
- The difference between a session token and a management key
- When a gateway JWT authorizer beats calling the SDK yourself
- That gateways handle signature and audience checks while your code still owns role logic

---

![Client SDK Integration. 2 minutes.](video:sdks-and-integration-client-sdk-integration)

Descope's client SDKs run in the browser. They render Flows, hold session and refresh tokens, and expose the current auth state to the rest of your app — but they never decide whether a request is authorized. There is a dedicated SDK for every major web framework: @descope/web-js-sdk for vanilla JavaScript, plus React, Vue, Angular, and Next.js packages, all wrapping the same underlying logic behind a framework-idiomatic API.

> [!WARNING]
> The default configuration stores the session token in browser localStorage, readable by any JavaScript on the page. That is a deliberate convenience tradeoff, not an oversight: if your threat model includes XSS, set persistTokens: false or move to sessionTokenViaCookie — at the cost of managing token storage yourself.

A Flow can render in three places: embedded inside your application, on a Descope-hosted page, or inside a mobile webview. All three run the exact same authentication logic and issue the exact same tokens. Embedded login drops a Flow component pointing at a flowId you designed in the Console; it renders inline with no redirect and no change of origin, so the user never leaves your app. Descope handles credential validation, OTP delivery, and token issuance; your job is the component, the flow ID, and a pair of onSuccess / onError callbacks.

The alternative is skipping Flows entirely and calling individual authentication methods yourself. That gives full control over every screen and error state, but you then own that UI — resend timers, MFA branching, and validation messaging all become your code rather than Console configuration. Of the three integration approaches (Flows with the Client SDK, Client SDK without Flows, Backend SDK only), the first is the fastest path to production and where most teams start.

Once a Flow completes via onSuccess — or you call manageSession after a manual auth call — the client SDK holds both tokens and refreshes them automatically. Whatever the framework, the pattern for calling your own backend is identical: read the session token from the SDK and send it as a Bearer token on the Authorization header of every request.

> [!NOTE]
> isJwtExpired() and getJwtRoles() are UI conveniences only. They exist to avoid a flash of the wrong screen, not to protect data — a button hidden by a role check does nothing for the API that button calls. Always log out through the SDK's logout() or logoutAll() rather than discarding local state, so the session is revoked server-side too.

## Key terms

- Client SDK — the framework-specific family running in the browser, managing tokens and optionally rendering Flows.
- persistTokens — controls whether session tokens are stored in browser localStorage.
- AuthProvider — the top-level wrapper that initializes the SDK and exposes session and user context.

## Summary

- That client SDKs manage tokens and render Flows but never authorize requests
- Why a team might disable persistTokens, and what that costs
- The difference between using Flows and calling auth methods directly
- That UI-only checks never replace backend validation

---

![Framework-Specific Patterns. 2 minutes.](video:sdks-and-integration-framework-specific-patterns)

## Client SDKs

- @descope/web-js-sdk — vanilla JavaScript
- @descope/react-sdk
- @descope/vue-sdk
- @descope/angular-sdk
- @descope/nextjs-sdk

## Backend SDKs

- Node.js
- Python
- Go
- Java
- Ruby
- PHP
- .NET

Descope's getting-started material is organized as pairs rather than as one list, because the question a team actually has is not "how do I use the React SDK" but "how do I wire React to my Go backend". Pick your frontend, pick your backend, and the guide covers the handoff between them — which is where integrations go wrong.

Two framework details are worth knowing because they are easy to miss. Next.js has authMiddleware, which validates the session and can redirect an unauthenticated user before the request reaches a page or API route — convenient, and not a substitute for authorization inside the route. And any client SDK can be pointed at a custom domain by setting the base URL, which has to match the domain your tokens were minted for or validation fails in a way that looks like a bad key.

> [!NOTE]
> If your framework has no Descope SDK at all, the OIDC endpoints are standard and documented. That is a supported integration path rather than a workaround — this app's own login is a hand-rolled OIDC handshake for exactly that reason.

Where teams do get stuck is rarely the SDK. It is deciding which half owns the session — whether the browser keeps a token and sends it, or a server-side session does the work and the browser only holds a cookie. Settle that first and the framework choice stops mattering much.

## Summary

- The one pattern every integration follows, regardless of stack
- Which client and backend SDKs exist
- Why the guides are organized as frontend-plus-backend pairs
- What authMiddleware does and does not cover, and why a custom domain changes the base URL
- That standard OIDC is a supported path when no SDK fits

---

![Hosted Flows and Auth Hosting. 3 minutes.](video:sdks-and-integration-hosted-flows-and-auth-hosting)

## Choosing between the three modes

- Embedded — users never leave the app, a frontend is required, customization is full. Best for web SPAs and consumer apps.
- Hosted — users do leave, no frontend needed, customization via custom domain, themes, and styles. Best for SaaS integrations, acting as an OIDC/SAML IdP, and no-code tools.
- Native Flows — users stay in the app via a webview, the mobile SDK is required, customization includes custom animations and transitions. Best for iOS and Android.

Three questions settle most decisions. Do you have your own frontend and want a seamless, same-origin experience? Embed it. Are you integrating with a platform or partner tool you do not control? Use hosted login. Are you building a mobile app? Use Native Flows. These are not mutually exclusive — plenty of teams embed login in their web app, use hosted login for third-party OIDC/SAML integrations, and use Native Flows on mobile, all from one project.

> [!NOTE]
> The security gap between embedded and hosted login mostly comes down to the auth method, not the rendering mode. With passwords, embedded login puts your frontend code between the user and Descope. With passwordless methods, no reusable secret ever touches your JavaScript, so that gap largely disappears.

## Key terms

- Auth Hosting — Descope's managed hosted-login page, optionally on a custom domain.
- Embedded login — rendering the Flow UI inside your application with no redirect and no change of origin.
- Native Flow — the mobile-specific mode running a hosted flow inside an in-app webview rather than an external browser.

## Summary

- What hosted login removes from your frontend's responsibilities
- Which mode fits an OIDC-based tool you do not control
- That updating a Flow propagates to all three modes immediately, with no redeploy
- That the real security difference is the auth method, not the rendering mode

---

![Mobile SDK Integration. 3 minutes.](video:sdks-and-integration-mobile-sdk-integration)

## The SDKs

- Swift — native iOS
- Kotlin — native Android
- Flutter — cross-platform
- React Native — cross-platform

Each manages the full session lifecycle on-device: secure storage, automatic refresh, logout, and attaching the session token to outgoing requests. Storage uses the platform's own secure store — Keychain on iOS, EncryptedSharedPreferences on Android — so tokens are never sitting in application preferences for anyone with a rooted device to read.

The more interesting part is Native Flows, which is how a hosted flow stops feeling like a detour. Most providers send a mobile user out to an external browser to authenticate. A Native Flow serves the same hosted page — Auth Hosting or your own self-hosted copy — inside a webview in your app, so the user never leaves it.

## What that buys you

- The flow is hosted remotely, so there is no authentication infrastructure to ship in the app
- It renders in a webview rather than an external browser, so branding and navigation stay yours
- Flows can be preloaded, so sign-in appears instantly rather than after a fetch
- Transitions and animations are yours to control, because the container is native

## Two shapes it usually takes

- Simple — push a flow view controller onto the navigation stack, presenting the hosted flow full-screen
- Modal — preload the controller so the flow appears in a modal the moment the user taps sign in, closer to a browser sheet than a full page

Because the flow is the same configuration your web app uses, a change in the Console reaches the mobile app without an App Store release. That is the practical argument for hosted flows on mobile: authentication changes stop being tied to a review cycle.

## Summary

- Which SDKs exist, and that the platform secure store is used rather than app preferences
- What a Native Flow is, and why it is a webview rather than an external browser
- The simple and modal presentations, and why preloading matters
- That flow changes reach mobile without shipping a build

---
