JWT Authentication
Identify users in your help widget without requiring a separate login. When users are logged into your app, you can pass their identity to Ferndesk using a JWT token signed by your backend.
You'll need your JWT secret from Help Center > Customize > Access Control and the Ferndesk SDK installed.
How It Works
Three-step flow:
Your frontend detects a logged-in user
Your backend generates a signed JWT with user details
Your frontend calls
Ferndesk('identify', { jwt })
The help center and widget now knows who the user is for authentication, personalization and analytics.
The identify method only works from the same domain as your help center or a 1-level subdomain. If your help center is at help.example.com, you can identify from app.example.com but not otherdomain.com.
JWT Secret
Before you can sign JWTs, you need a signing secret from your Ferndesk dashboard:
Go to Help Center, then under Manage, click Access Control.
Expand the JWT identification row
Click Generate Secret
You can only create one JWT secret per help center. If a secret already exists, you'll need to delete it before generating a new one.
The secret is shown only once when you generate it. Copy it immediately and store it securely in your backend environment variables. You won't be able to view it again.
If you lose your secret, you'll need to delete it and generate a new one. This will invalidate all existing JWT tokens signed with the old secret until you update your backend to use the new one.
Generate the JWT Server-Side
Create an endpoint that returns a signed token. Required claims:
sub(string, required): Unique ID in your system that identifies this user. This is the primary identity key.email(string, required): User's email addressname(string, optional): Display namecustomAttributes(object, optional): Extra metadataexp(number, recommended): Token expiration timestamp
The sub claim must remain stable for each user. Ferndesk uses this subject to identify and link users. If a user's sub changes, they will not be linked to their previous help center identity.
Node.js example:
const jwt = require('jsonwebtoken');
app.get('/api/ferndesk-token', async (req, res) => {if (!req.user) return res.status(401).json({ error: 'Not authenticated' });
const token = jwt.sign({
sub: req.user.id,
email: req.user.email,
name: req.user.name,
exp: Math.floor(Date.now() / 1000) + 3600 // 1 hour
}, process.env.FERNDESK_JWT_SECRET, { algorithm: 'HS256' });
res.send(token);
});Python example:
import jwt
import time
@app.route('/api/ferndesk-token')
def ferndesk_token():
if not current_user:
return {'error': 'Not authenticated'}, 401
token = jwt.encode({
'sub': current_user.id,
'email': current_user.email,
'name': current_user.name,
'exp': int(time.time()) + 3600
}, os.environ['FERNDESK_JWT_SECRET'], algorithm='HS256')
return tokenNever expose your JWT secret in client-side code. Store it in environment variables server-side only.
Call Identify from Your Frontend
Fetch the token from your backend and pass it to the SDK:
Ferndesk('init', { widgetId: 'your-widget-id' });
fetch('/api/ferndesk-token').then(r => r.text())
.then(jwt => Ferndesk('identify', { jwt }))
.catch(err => console.error('Identification failed:', err));React example:
useEffect(() => {
window.Ferndesk('init', { widgetId: 'your-widget-id' });
if (currentUser) {
fetch('/api/ferndesk-token')
.then(r => r.text())
.then(jwt => window.Ferndesk('identify', { jwt }));
}
}, [currentUser]);Call identify after init but before opening the widget. To log out, reinitialize without calling identify.
Verify It's Working
Check these indicators:
Browser console: No errors. Invalid JWTs show
Ferndesk: identify failed - invalid jwtContact form: Email and name will be pre-filled
Analytics: User sessions appear in your dashboard
Common Errors
Ferndesk: identify requires a jwt
Missing jwt parameter. Check that your backend is returning a JWT string.
invalid jwt
Signature verification failed. Verify:
Correct JWT secret matches what's stored in Ferndesk
Token hasn't expired
Algorithm is HS256
JWT subject does not match the existing help-center user
This error occurs when a user's email already exists in your help center but with a different subject ID. This means someone previously signed in with that email using a different identity system or sub value.
To resolve:
Ensure your backend always sends the same
subfor each userIf you've changed user ID systems, the affected user will need to be re-provisioned in Ferndesk
must be called from same domain or 1-level subdomain
Domain mismatch. Your app and help center must share a root domain.
The sub claim is the primary identifier for users. While email is required, Ferndesk binds identity to the subject, not the email address alone. This prevents account takeover if email addresses change or are reused.
Security Notes
Set token expiration (1 hour is common)
Only generate tokens for authenticated users
Use HTTPS everywhere
Never commit secrets to version control
Keep your
subvalues stable—Ferndesk persists identity by subject