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', { token })
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.
Generate the JWT Server-Side
Create an endpoint that returns a signed token. Required claims:
userId(string): Unique ID in your systememail(string): User's emailname(string, optional): Display namecustomAttributes(object, optional): Extra metadataexp(number, recommended): Token expiration timestamp
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({
userId: 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({
'userId': current_user.id,
'email': current_user.email,
'name': current_user.name,
'exp': int(time.time()) + 3600
}, os.environ['FERNDESK_JWT_SECRET'], algorithm='HS256')
return token Never 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(token => Ferndesk('identify', { token }))
.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(token => window.Ferndesk('identify', { token }));
}
}, [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 tokens show
Ferndesk: identify failed - invalid tokenContact form: Email and name will be pre-filled
Analytics: User sessions appear in your dashboard
Common Errors
identify requires a token
Missing token parameter. Check your backend is returning a JWT string.
invalid token
Signature verification failed. Verify:
Correct JWT secret
Token hasn't expired
Algorithm is HS256
must be called from same domain or 1-level subdomain
Domain mismatch. Your app and help center must share a root domain.
Security Notes
Set token expiration (1 hour is common)
Only generate tokens for authenticated users
Use HTTPS everywhere
Never commit secrets to version control