User Impersonation | PropelAuth BYO Documentation

User Impersonation

When customers report bugs you can’t reproduce, impersonation lets your support and engineering teams see exactly what users see.

PropelAuth BYO Impersonation provides secure, time-limited access to act as any user. It tracks who impersonated whom, lets you instantly revoke access, and distinguishes impersonation sessions from regular sessions so you can add your own logging or restrictions.

How Impersonation Works

Impersonation involves two parties: an employee (someone on your team) and a user (your customer).

  1. Employee initiates - A support agent or engineer starts an impersonation session from your admin dashboard
  2. System creates token - PropelAuth BYO generates a special impersonation token tied to both the employee and user
  3. Employee uses token - The token lets the employee access your app as the user
  4. Session is distinguishable - Your app knows this is an impersonation session, not a regular login
  5. Session expires - After a set time (default: 1 hour), the session automatically ends

The beauty is that your application code barely changes. You validate impersonation tokens almost exactly like regular session tokens, just with a different function call.

Basic Usage

Let’s walk through implementing impersonation in your application.

Creating an Impersonation Session

To begin, you’ll need to set up a route that your employees can call to create an impersonation session:

Node

app.post("/api/admin/impersonate", async (req, res) => {
    // Get the employee from your auth system (e.g., from their session)
    const employeeEmail = getEmployeeEmail(req);
    const { userId } = req.body;

// Create the impersonation session
    const result = await auth.impersonation.create({
        employeeEmail: employeeEmail,
        targetUserId: userId,
        userAgent: req.headers["user-agent"],
        ipAddress: req.ip,
    });

if (!result.ok) {
        if (result.error.type === "UnauthorizedEmployee") {
            return res.status(403).json({ error: "Not authorized to impersonate" });
        }
        console.error("Failed to create impersonation session:", result.error);
        return res.status(500).json({ error: "Failed to create impersonation session" });
    }

// We recommend using the same cookie that your regular sessions use to avoid ambiguity
    res.cookie("sessionToken", result.data.impersonationSessionToken, {
        httpOnly: true,
        secure: true,
        sameSite: "lax",
        maxAge: 60 * 60 * 1000, // 1 hour
    });

res.json({ success: true });
});

Python

class ImpersonateRequest(BaseModel):
    user_id: str
@app.post("/api/admin/impersonate")
async def impersonate(impersonate_request: ImpersonateRequest, request: Request, response: Response):
    # Get the employee from your auth system (e.g., from their session)
    employee_email = get_employee_email(request)

# Create the impersonation session
    result = await client.impersonation.create(
        employee_email=employee_email,
        target_user_id=impersonate_request.user_id,
        user_agent=request.headers.get("user-agent"),
        ip_address=request.client.host
    )

if not is_err(result):
        if result.error.type == "UnauthorizedEmployee":
            raise HTTPException(status_code=403, detail="Not authorized to impersonate")
        print("Failed to create impersonation session:", result.error)
        raise HTTPException(status_code=500, detail="Failed to create impersonation session")

# We recommend using the same cookie that your regular sessions use to avoid ambiguity
    response.set_cookie(
        key="sessionToken",
        value=result.data.impersonation_session_token,
        httponly=True,
        secure=True,
        samesite="lax",
        max_age=60 * 60  # 1 hour
    )

return {"success": True}

Validating Sessions (Regular or Impersonation)

Use the same cookie for both regular and impersonation sessions, checking the prefix to determine which validation to use:

Node

// GET /api/user/profile
app.get("/api/user/profile", async (req, res) => {
    const sessionToken = req.cookies.sessionToken;
    if (!sessionToken) {
        return res.status(401).json({ error: "Not authenticated" });
    }

// Check if this is an impersonation session
    if (sessionToken.startsWith("impersonate_")) {
        return validateImpersonationSession(sessionToken);
    } else {
        return validateRegularSession(sessionToken);
    }
});

Ending Sessions

Your logout endpoint should handle invalidating both regular and impersonation sessions:

// POST /api/logout
app.post("/api/logout", async (req, res) => {
    const sessionToken = req.cookies.sessionToken;
    if (!sessionToken) {
        return res.status(200).json({ success: true });
    }

if (sessionToken.startsWith("impersonate_")) {
        // Handle impersonation sessions
        await auth.impersonation.invalidateByToken({
            impersonationSessionToken: sessionToken,
        });
    } else {
        // This is your existing logout logic
        await logoutOurSession(sessionToken);
    }

// Clear the session cookie
    res.clearCookie("sessionToken");
    res.json({ success: true });
});

Configuring Who Can Impersonate

Not everyone should be able to impersonate users. PropelAuth BYO gives you three ways to control access through your user_impersonation.jsonc configuration file:

{
    "absolute_lifetime_secs": 3600, // 1 hour
    "who_can_impersonate": {
        "allowed_employee_emails": ["support@company.com", "john@company.com"],
    }
}

Security Considerations

Impersonation Audit Trail

PropelAuth BYO maintains a complete audit trail of impersonation sessions:

Instant Revocation

Immediately revoke access when needed using either the Invalidate All For Employee or Invalidate All for User functions:

// Revoke all sessions for a compromised employee account
await auth.impersonation.invalidateAllForEmployee({
    employeeEmail: "compromised@company.com",
});
// Stop all impersonation of a specific user
await auth.impersonation.invalidateAllForUser({
    userId: sensitiveUserId,
});

Restricting Actions During Impersonation

Since you can detect when someone is impersonating, you can prevent sensitive actions:

// Any sessions validated with client.impersonation.validate() should add a flag like this
if (user.isImpersonation) {
    // Block sensitive operations like payment changes
    return res.status(403).json({
        error: "Cannot modify payment methods during impersonation",
    });
}

Working with Sessions

Impersonation tokens work seamlessly with PropelAuth BYO’s session management. You can use the same patterns and features:

// Impersonation benefits from session features
const result = await client.impersonation.create({
    employeeEmail: employeeEmail,
    targetUserId: userId,
    userAgent: req.headers["user-agent"],
    ipAddress: req.ip,
    metadata: {
        ticketId: "SUPPORT-1234",
        reason: "Customer requested help with billing",
    },
});

Dashboard Management

The PropelAuth BYO dashboard gives you visibility into all impersonation activity: Active Sessions - View current impersonation sessions with who is impersonating whom, start time, and quick invalidation.

Audit Trail - Complete history of who impersonated whom, when sessions started/ended, and any manual invalidations.

Emergency Controls - Invalidate all sessions for an employee, block specific employees, or stop all impersonation of a user.