Skip to main content
Technology & EngineeringAuth Services270 lines

Descope

Integrate Descope to add secure, no-code/low-code authentication and user management to your applications.

Quick Summary23 lines
You are an authentication specialist who leverages Descope to rapidly build secure, flexible, and user-friendly identity experiences. You understand how Descope’s drag-and-drop flows and SDKs enable you to integrate complex authentication methods with minimal code, while maintaining full control over your frontend UI.

## Key Points

*   **Always Verify Sessions on the Backend:** Never trust client-side authentication status. Your backend must validate the Descope session token for every protected API request.
*   **Use Environment Variables:** Store `DESCOPE_PROJECT_ID` and `DESCOPE_MANAGEMENT_KEY` securely as environment variables, never hardcode them in your codebase.
*   **Leverage Descope Flows:** For most user-facing authentication actions (sign-up, login, password reset), use the pre-built and secure Descope flows via the `<Descope />` component.
*   **Implement Robust Error Handling:** Handle `onDescopeError` on the frontend and `try/catch` blocks on the backend to provide meaningful feedback to users and log issues.
*   **Customize via Console, Not Code:** For visual customization of flows, use the Descope Console's UI builder and theming options rather than trying to override styles extensively in your app.
*   **Keep SDKs Updated:** Regularly update your Descope SDKs to benefit from the latest features, security patches, and performance improvements.
*   **Monitor Descope Logs:** Utilize Descope's logging and auditing features in the Console to monitor authentication events and detect suspicious activity.

## Quick Example

```bash
# Frontend (React)
npm install @descope/react-sdk @descope/web-component

# Backend (Node.js)
npm install @descope/node-sdk
```
skilldb get auth-services-skills/DescopeFull skill: 270 lines
Paste into your CLAUDE.md or agent config

You are an authentication specialist who leverages Descope to rapidly build secure, flexible, and user-friendly identity experiences. You understand how Descope’s drag-and-drop flows and SDKs enable you to integrate complex authentication methods with minimal code, while maintaining full control over your frontend UI.

Core Philosophy

Descope is built on the principle of making authentication simple, secure, and accessible for developers. It offers a no-code/low-code platform where you design your authentication flows visually using a drag-and-drop interface, then integrate these pre-built, secure flows into your application using their SDKs. This approach offloads the immense complexity and security burden of managing user registration, login, session handling, and advanced methods like Passkeys, Magic Links, and SAML/SSO to a specialized, managed service.

When you choose Descope, you are prioritizing developer velocity and security by default. It handles the intricate details of cryptographic key management, secure session cookies, and multi-factor authentication, allowing you to focus on your application's unique value proposition. Descope provides a unified API and SDKs for various platforms, ensuring consistent and secure authentication experiences across web, mobile, and backend services, while giving you the flexibility to customize the look and feel of your authentication UI.

Setup

To integrate Descope, you first need to create a project in the Descope Console and obtain your Project ID. Then, install the relevant Descope SDK for your frontend and backend.

1. Install SDKs:

For a React frontend and Node.js backend:

# Frontend (React)
npm install @descope/react-sdk @descope/web-component

# Backend (Node.js)
npm install @descope/node-sdk

2. Initialize Descope on the Frontend:

Wrap your application with the Descope context provider and configure it with your Project ID.

// src/App.tsx
import React from 'react';
import { Descope } from '@descope/react-sdk';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import Profile from './Profile';

function App() {
  return (
    <Router>
      <Descope projectId={process.env.REACT_APP_DESCOPE_PROJECT_ID || ''}>
        <nav>
          <Link to="/">Home</Link> | <Link to="/profile">Profile</Link>
        </nav>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/profile" element={<Profile />} />
        </Routes>
      </Descope>
    </Router>
  );
}

export default App;

3. Initialize Descope on the Backend:

Configure the Node.js SDK with your Project ID and Management Key (for programmatic user management).

// src/server.js
const DescopeClient = require('@descope/node-sdk').default;
require('dotenv').config();

const descopeClient = DescopeClient({
  projectId: process.env.DESCOPE_PROJECT_ID,
  managementKey: process.env.DESCOPE_MANAGEMENT_KEY // Only needed for management API calls
});

// For session validation, you only need the projectId
const descopeAuthClient = DescopeClient({
  projectId: process.env.DESCOPE_PROJECT_ID
});

// Use descopeAuthClient for session validation middleware, descopeClient for user management.

Ensure DESCOPE_PROJECT_ID and DESCOPE_MANAGEMENT_KEY are stored as environment variables.

Key Techniques

1. Integrating Authentication Flows with <Descope /> Component

Embed a pre-configured authentication flow directly into your React application using the @descope/react-sdk. This example renders a sign-up/sign-in flow.

// src/Home.tsx
import React from 'react';
import { Descope, useDescope } from '@descope/react-sdk';
import { useNavigate } from 'react-router-dom';

const Home: React.FC = () => {
  const { authenticated, user, logout } = useDescope();
  const navigate = useNavigate();

  const onDescopeSuccess = (e: any) => {
    console.log('User logged in!', e.detail.user);
    // Redirect to profile or dashboard after successful login
    navigate('/profile');
  };

  const onDescopeError = (err: any) => {
    console.error('Login error:', err);
    // Handle login error, e.g., display a message
  };

  return (
    <div>
      <h1>Welcome to the App</h1>
      {!authenticated ? (
        <>
          <p>Please sign up or log in to continue.</p>
          <Descope
            flowId="sign-up-or-in" // This flowId should match a flow configured in your Descope Console
            onSuccess={onDescopeSuccess}
            onError={onDescopeError}
            redirectUrlAfterPostLogin="/profile" // Optional: Redirect after flow completion
            theme="light"
          />
        </>
      ) : (
        <>
          <p>Hello, {user?.name || user?.email || user?.loginIds?.[0]}!</p>
          <button onClick={logout}>Logout</button>
        </>
      )}
    </div>
  );
};

export default Home;

2. Protecting Backend Routes with Session Verification

Implement middleware on your backend to verify the Descope session token sent from the client. This ensures only authenticated users can access protected resources.

// src/server.js (continued)
const express = require('express');
const cookieParser = require('cookie-parser');
const jwt = require('jsonwebtoken'); // For local token decoding if needed, Descope SDK handles verification

const app = express();
app.use(express.json());
app.use(cookieParser()); // Descope stores tokens in cookies by default

// Middleware to verify Descope session
const authenticateUser = async (req, res, next) => {
  try {
    const sessionToken = req.cookies.DS; // Descope's default session cookie name
    if (!sessionToken) {
      return res.status(401).json({ error: 'No session token found' });
    }

    // Verify the session token using Descope SDK
    const authInfo = await descopeAuthClient.validateSession(sessionToken);
    
    // Attach user info to request
    req.user = authInfo.token; // The decoded JWT payload
    req.sessionId = authInfo.sessionJwt.sid; // Session ID
    next();
  } catch (error) {
    console.error('Session validation failed:', error);
    res.status(401).json({ error: 'Invalid or expired session' });
  }
};

// Protected route example
app.get('/api/profile', authenticateUser, (req, res) => {
  res.json({
    message: 'Welcome to your profile!',
    user: req.user,
    sessionId: req.sessionId
  });
});

// Start server
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`Backend server running on port ${PORT}`);
});

3. Programmatic User Management (Backend)

Use the Descope Management SDK to perform actions like creating new users, updating user profiles, or deleting users directly from your backend. This requires a managementKey.

// src/adminService.js (example of a backend service)
const DescopeClient = require('@descope/node-sdk').default;
require('dotenv').config();

const descopeClient = DescopeClient({
  projectId: process.env.DESCOPE_PROJECT_ID,
  managementKey: process.env.DESCOPE_MANAGEMENT_KEY
});

// Function to create a new user
async function createUser(email, name, password) {
  try {
    const user = await descopeClient.management.user.create(
      email,
      password ? password : undefined, // Password is optional if using other auth methods
      true, // Verified
      { name: name }
    );
    console.log('User created:', user);
    return user;
  } catch (error) {
    console.error('Error creating user:', error);
    throw error;
  }
}

// Function to update a user's name
async function updateUserName(userId, newName) {
  try {
    const user = await descopeClient.management.user.update(
      userId,
      {
        name: newName
      }
    );
    console.log('User updated:', user);
    return user;
  } catch (error) {
    console.error('Error updating user:', error);
    throw error;
  }
}

// Example usage (e.g., in an admin route)
// app.post('/api/admin/users', async (req, res) => {
//   try {
//     const { email, name, password } = req.body;
//     const newUser = await createUser(email, name, password);
//     res.status(201).json(newUser);
//   } catch (error) {
//     res.status(500).json({ error: error.message });
//   }
// });

Best Practices

  • Always Verify Sessions on the Backend: Never trust client-side authentication status. Your backend must validate the Descope session token for every protected API request.
  • Use Environment Variables: Store DESCOPE_PROJECT_ID and DESCOPE_MANAGEMENT_KEY securely as environment variables, never hardcode them in your codebase.
  • Leverage Descope Flows: For most user-facing authentication actions (sign-up, login, password reset), use the pre-built and secure Descope flows via the <Descope /> component.
  • Implement Robust Error Handling: Handle onDescopeError on the frontend and try/catch blocks on the backend to provide meaningful feedback to users and log issues.
  • Customize via Console, Not Code: For visual customization of flows, use the Descope Console's UI builder and theming options rather than trying to override styles extensively in your app.
  • Keep SDKs Updated: Regularly update your Descope SDKs to benefit from the latest features, security patches, and performance improvements.
  • Monitor Descope Logs: Utilize Descope's logging and auditing features in the Console to monitor authentication events and detect suspicious activity.

Anti-Patterns

  • Client-Side Only Session Checks. You should never rely solely on useDescope().authenticated or the presence of a cookie on the client side to determine if a user can access sensitive data or perform critical actions. Always perform server-side validation using descopeAuthClient.validateSession() to secure your APIs.
  • Hardcoding API Keys or Project IDs. Storing sensitive credentials directly in your source code or client-side JavaScript is a major security risk. Always use environment variables for DESCOPE_PROJECT_ID and DESCOPE_MANAGEMENT_KEY.
  • Building Custom Authentication UIs from Scratch for Core Flows. While Descope offers flexibility, trying to completely rebuild basic login/signup forms and handling all the intricate logic yourself defeats the purpose of Descope's secure, pre-built flows. Use the <Descope /> component and customize its appearance through the Descope Console.
  • Ignoring onSuccess / onError Callbacks. Failing to implement these callbacks means you're not reacting to the outcomes of the authentication flow, leading to poor user experience (e.g., not redirecting after login) or silent failures.
  • Using the Management Key on the Frontend. The DESCOPE_MANAGEMENT_KEY grants powerful programmatic access to your Descope project and should only be used on your secure backend servers, never exposed to the client.

Install this skill directly: skilldb add auth-services-skills

Get CLI access →