Transitioning to JWT-Based authentication for better security
A technical guide for migrating user authentication from HMAC-based identity verification to JWT tokens, covering implementation steps, security benefits, and code examples for enhanced user session protection.
Written By Bruno from Featurebase
Last updated 4 months ago
Why Migrate from Identity Verification to JWTs?
Featurebase's traditional Identity Verification uses HMAC-SHA256 hashes to verify user authenticity. While this prevents basic impersonation attacks, JWTs offer significant improvements:
Enhanced Security Features
Protect all attributes: Current solution provides limited control over data security, only the customer identifier is verified (e.g., user email/id or company id), while other attributes (e.g., customer plan) can not be verified. With JWTs, you can verify every attribute needed.
Time-based validity: Unlike static user hashes, JWT tokens automatically expire after a specified duration
Protection against replay attacks: Time-limited tokens reduce vulnerability windows
Operational Benefits
Selective data protection: Specify which user attributes require secure transmission
Better scalability: More suitable for distributed systems and modern architectures
Session management flexibility (Coming soon): Define custom expiration periods based on your security requirements
Technical Comparison
Current Identity Verification (HMAC Hashing)
Uses static userHash and optional companyHash
Generated using HMAC-SHA256 with your secret key
No built-in expiration mechanism
Suitable for basic verification needs
JWT Approach
Granular control over protected attributes
Dynamic token generation with embedded claims
Configurable expiration timestamps (Coming soon)
Aligned with current security standards
A single token contains all authentication data
Migration Process
Step 1: Copy Your JWT Secret Key
Navigate to Settings β Security in your Featurebase dashboard and copy your JWT secret value.
Step 2: Update Backend Token Generation
Replace your current HMAC hash generation with JWT creation:
Before (Identity Verification):
Exampleimport crypto from "crypto";
// Your identity verification secret
const secretKey = "iv_your-secret-key";
// Use email or user identifier
const userIdentifier = currentUser.email;
// Generate HMAC hash
const userHash = crypto
.createHmac('sha256', secretKey)
.update(userIdentifier)
.digest('hex');After (JWT Authentication):
Exampleconst jwt = require("jsonwebtoken");
// Configure token payload
const tokenData = {
name: currentUser.name,
// Both email and userId should be provided when possible
// At minimum, either email or userId must be present
email: currentUser.email,
userId: currentUser.userId,
profilePicture: "https://example.com/images/yourcustomer.png",
// Add any optional custom attributes - must be configured from settings to work
title: "Product Manager",
plan: "Premium",
number: "123",
// locale: "en", // optional, provide expected language for user
// Optional fields
companies: [
{
id: "987654321", // required
name: "Business Inc. 23", // required
monthlySpend: 500, // optional
createdAt: "2023-05-19T15:35:49.915Z", // optional
// Add any optional custom attributes - must be configured from settings to work
industry: "Fintech",
location: "Canada",
},
],
};
// Use environment variable for security
const signingKey = process.env.FEATUREBASE_JWT_SECRET;
// Generate signed token
const authToken = jwt.sign(tokenData, signingKey, {
algorithm: "HS256"
});Step 3: Update Frontend Implementation
Modify your Featurebase identify calls to use JWT instead of userHash:
Before (Identity Verification):
ExampleFeaturebase("boot", {
appId: "yourAppId",
email: "user@example.com",
name: "User Name",
userId: "123456",
userHash: "user-hash-for-this-specific-user",
createdAt: "2025-05-06T12:00:00Z",
// ... other fields
companies: [{
id: "123",
companyHash: "company-hash-created-from-company-id",
// ... other fields
}]
});After (JWT Authentication):
ExampleFeaturebase("boot", {
appId: "yourAppId",
featurebaseJwt: "generated-jwt-here", // Required for secure auth - JWT generated on your server
nonSensitiveAttr1: "non-sensitive-value", // Optional
nonSensitiveAttr2: "non-sensitive-value", // Optional
nonSensitiveAttr3: "non-sensitive-value", // Optional
});For non-sensitive attributes, you may still include them directly in the code snippet outside of the JWT payload.
Step 4: Configure Secure Attribute Updates
In your Featurebase dashboard:
Navigate to Settings β Data β User Attributes
For each sensitive attribute included in your JWT payload, edit it and enable "Require secure updates"
This ensures these attributes can only be modified through authenticated requests
Repeat for Company custom attributes if needed
Step 5: Testing Your Implementation
Before enforcing JWT authentication:
Use the hash checker at Settings β Security to validate your JWT generation
Test with non-admin accounts (admin auto-login is disabled for security)
Check browser console for any authentication errors
Verify that user data syncs correctly
Test token expiration and refresh flows
Step 6: Cleanup
Once testing is complete:
Remove userHash generation from your backend code
Clean up any client-side code sending userHash parameters
Migration Considerations
Backward Compatibility
Featurebase will accept both valid user hashes and JWTs. This allows for gradual migration without service disruption.
Data Attributes in JWTs
All user and company data should now be included in the JWT payload rather than sent separately. This includes:
User identification (email, userId, name)
Company associations
Custom fields and attributes
Monthly spend or other metrics
Security Best Practices
Token Management
Store JWT signing keys securely (environment variables, key vaults)
Never expose keys in client-side code or repositories
Use different keys for development and production environments
Troubleshooting Common Issues
Invalid JWT Errors
If you see 400 Bad Request errors:
Verify you're using the correct signing key
Check that the required fields (userId or email) are included
Ensure the token hasn't expired
Validate your JWT structure using the dashboard tools
User Not Identified
Confirm JWT is being passed in the identify or messenger boot call
Check that the organization name matches your Featurebase subdomain
Verify token signature using the correct algorithm (HS256)
Data Not Syncing
Ensure all user attributes are included in the JWT payload
Check that "Require secure updates" is configured correctly
Verify company data structure matches expected format
FAQ
Getting Help
For additional support during migration:
Contact Featurebase support with any error messages
Include your organization name and example JWT
Conclusion
Migrating from Identity Verification to JWT-based authentication strengthens your Featurebase security posture while providing better control over user sessions and data. The transition can be done gradually without disrupting existing users, making it a low-risk, high-reward security upgrade for your feedback and support platform.