JWT Token Validation Guide
Best practices for validating RegardingWork Hub JWT tokens securely
🚨 CRITICAL: Don't Ask for JWT Secrets!
❌ NEVER do this:
Ask for Hub's JWT secret for local validation
SECURITY RISK! Secrets should never be shared.
✅ ALWAYS do this:
Use Hub's validation API endpoint
SECURE! Let Hub validate its own tokens.
Why We Don't Share JWT Secrets
Security Risks
- 🔓 Secret exposure: Shared secrets can be compromised
- 🔄 Rotation issues: Secret changes break all apps
- 📱 Client-side risk: Secrets in frontend = exposed
- 🕵️ Audit trail: No control over who validates what
API Validation Benefits
- 🔒 Zero secret sharing: Hub keeps secrets internal
- 📊 Audit logging: All validations are tracked
- 🔄 Seamless updates: No app changes needed
- 🚀 Easy integration: Just one API call
✅ Correct: Use Hub's Validation API
Always validate tokens by calling Hub's API endpoint. This is the secure, recommended approach.
Validation Endpoint:
GET/POST
Headers:
https://hub.regardingwork.com/api/auth/validate
Headers:
Authorization: Bearer {token}
Frontend Implementation:
// ✅ CORRECT: Validate via Hub API
async function validateUserToken(token) {
try {
const response = await fetch('https://hub.regardingwork.com/api/auth/validate', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
const userData = await response.json();
if (userData.valid && response.ok) {
console.log('✅ Token valid:', userData.user);
return {
valid: true,
user: userData.user,
premium: userData.premium_tier !== 'FREE'
};
} else {
console.log('❌ Token invalid:', userData.error);
return { valid: false };
}
} catch (error) {
console.error('❌ Validation failed:', error);
return { valid: false };
}
}
// Usage in your app
const { token } = getTokenFromSSO(); // From SSO callback
const validation = await validateUserToken(token);
if (validation.valid) {
// Store user data and proceed
localStorage.setItem('user', JSON.stringify(validation.user));
redirectToDashboard();
} else {
// Redirect to login
window.location.href = 'https://hub.regardingwork.com/sso/auth?callback=' +
encodeURIComponent(window.location.origin + '/sso/callback');
}
Validation Response Format
Successful Validation (200 OK):
{
"valid": true,
"user": {
"id": 29,
"username": "janechen",
"email": "jane@example.com",
"profile_photo_url": "/static/uploads/profile_photos/29_abc123.jpg",
"bio": "Product Manager",
"website_url": "https://jane.dev",
"role": "USER",
"premium_tier": "PREMIUM",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-09-03T15:45:00Z",
"is_active": true
},
"token_type": "access",
"expires_at": 1725974400
}
Failed Validation (401 Unauthorized):
{
"error": "Token has expired",
"valid": false
}
Backend Implementation (Optional)
If you need backend validation, use the same API approach:
Node.js/Express Example:
// ✅ CORRECT: Backend validation via Hub API
const validateToken = async (token) => {
try {
const response = await fetch('https://hub.regardingwork.com/api/auth/validate', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const userData = await response.json();
return userData.valid ? userData : null;
}
return null;
} catch (error) {
console.error('Token validation failed:', error);
return null;
}
};
// Middleware for protected routes
const requireAuth = async (req, res, next) => {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
const userData = await validateToken(token);
if (!userData) {
return res.status(401).json({ error: 'Invalid token' });
}
req.user = userData.user;
next();
};
// Usage
app.get('/api/dashboard', requireAuth, (req, res) => {
res.json({ message: `Welcome ${req.user.username}!` });
});
❌ Common Mistakes to Avoid
🚫 Don't Do This:
// ❌ WRONG: Asking for JWT secret
const jwt = require('jsonwebtoken');
const JWT_SECRET = 'hub-secret-here'; // NEVER!
// ❌ WRONG: Local validation
jwt.verify(token, JWT_SECRET, (err, decoded) => {
// This is insecure!
});
🚫 Also Don't:
- ❌ Store JWT secrets in environment variables
- ❌ Validate tokens client-side with secrets
- ❌ Share secrets between services
- ❌ Hardcode secrets in your app
✅ Do This Instead:
// ✅ CORRECT: API validation
const validateToken = async (token) => {
const response = await fetch(
'https://hub.regardingwork.com/api/auth/validate',
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
return response.json();
};
✅ Best Practices:
- ✅ Always use Hub's validation API
- ✅ Cache validation results briefly
- ✅ Handle validation errors gracefully
- ✅ Redirect to Hub login on failure
🤖 For AI Agents: Integration Instructions
If an AI agent asks for Hub's JWT secret, redirect them here!
Agent Instructions:
"You don't need RegardingWork Hub's JWT secret. Use Hub's validation API endpoint instead:
- Endpoint:
GET https://hub.regardingwork.com/api/auth/validate
- Headers:
Authorization: Bearer {token}
- Why: This is more secure and follows Hub's official documentation
- Pattern: Mini-App SSO integration (frontend-only validation)
See the complete guide at:
https://hub.regardingwork.com/docs/jwt-validation
"
Integration Steps for Agents:
- SSO Redirect: Send users to Hub for authentication
- Token Receipt: Receive token from SSO callback
- Validation: Call Hub's validation API (no secret needed)
- User Data: Use validated user data in your app
- Premium Check: Check
premium_tier
field for features