Configuring JWT Single Sign-On (SSO) with Benji Pays
To enable Single Sign-On (SSO) using JSON Web Tokens (JWT) in Benji Pays, follow the steps outlined below. This guide will ensure your integration meets the requirements for secure authentication.
Step 1: Set Up the SSO Configuration in Benji Pays
- Log in to Benji Pays.
- Navigate to Settings » Customer Portal Settings » SSO Configuration.
- Click on Add Configuration.
- Select JWT as the SSO type.
Complete the Form
- Description: Provide a descriptive name for this SSO configuration.
- Remote Login URL: Enter the URL where users will be sent to log in on your system (e.g.,
https://your-sso-provider.com/login
). This is also where users will be redirected if authentication errors occur. - Login Redirect URL: This URL is automatically generated. It points to the callback endpoint on Benji Pays (e.g.,
https://yourportaldomain.com/callbackjwt
). - ISS (Issuer): This value will act as the
iss
claim in your JWT payload. - Login Button Text: Customize the button text that users will see for SSO login.
Once the form is complete, click Save.
Obtain Key Configuration Details
After saving, the form will display the following critical information that you'll need to configure your JWT:
- AUDIENCE: The expected audience (
aud
) for the JWT. - ISSUER (ISS): The value to include in the
iss
claim. - CLIENTID: Your unique client identifier.
- CLIENTSECRET: Your shared secret for signing JWTs.
Step 2: Generate the JWT
Your system will generate a JWT containing the required claims and send it as part of the authentication process.
JWT Requirements
- Header:
{ "alg": "HS256", "typ": "JWT" }
- Payload:
The payload must include the following claims:
iss
(Issuer): Use the value provided in the ISS field from your SSO configuration.aud
(Audience): Use the value provided in the AUDIENCE field.exp
(Expiration Time): The token must expire no more than 5 minutes from the time of issuance.iat
(Issued At): The time the token was issued. The token must not have been issued more than 30 seconds in the past when Benji Pays receives it.email
: The email address of the user.sub
: This is the unique ID for your user that will not change and is unique and does not match their email address.client_id
: The unique Client ID provided in your SSO configuration.- NEW:
emailVerified
(Optional): Boolean value indicating if the user's email has been verified by your system. See Email Verification section below.
Example Payload (Basic):
{ "iss": "paxxxxxps-jwt-dxxxxxx4", "aud": "BENJIPAYS", "exp": 1700000000, "iat": 1699999400, "email": "user@example.com", "sub": "user_12345", "client_id": "provided-client-id" }
Example Payload (With Email Verification):
{ "iss": "paxxxxxps-jwt-dxxxxxx4", "aud": "BENJIPAYS", "exp": 1700000000, "iat": 1699999400, "email": "user@example.com", "sub": "user_12345", "client_id": "provided-client-id", "emailVerified": true }
- Signature:
The JWT must be signed using the CLIENTSECRET with the
HS256
algorithm.
Email Verification (NEW FEATURE)
You can now indicate whether a user's email has been verified by your system, eliminating redundant verification steps.
How It Works
- With emailVerified: true - User goes directly to the dashboard (no email verification required)
- With emailVerified: false or missing - User must verify their email through Benji Pays (traditional flow)
Usage Examples
Skip Email Verification (Recommended for verified users):
const token = jwt.sign({ // ... required claims ... emailVerified: true // User has verified email in your system }, clientSecret);
Require Email Verification:
const token = jwt.sign({ // ... required claims ... emailVerified: false // Or omit this claim entirely }, clientSecret);
Security Requirements
- Only boolean
true
is trusted - Strings like"true"
or numbers like1
will be ignored - Use only for verified emails - Only set
emailVerified: true
if you have actually verified the user's email - Backward compatible - Existing integrations continue to work without changes
Step 3: Submit the JWT
Once the JWT is generated, it must be submitted via a POST request to the /callbackjwt
endpoint.
Form Submission
- Form Method: POST
- Action:
https://yourportaldomain.com/callbackjwt
- Hidden Form Field:
- Name:
token
- Value: The JWT string.
- Name:
Example Form:
<!DOCTYPE html> <html> <head> <title>SSO Login</title> </head> <body> <form action="https://yourportaldomain.com/callbackjwt" method="POST"> <input type="hidden" name="token" value="YOUR_JWT_HERE"> <button type="submit">Login with ACME Co.</button> </form> <script> // Optional: Auto-submit the form document.forms[0].submit(); </script> </body> </html>
Step 4: Authentication Flow
- Users click the SSO login button in the customer portal.
- They are redirected to your system’s login page via the Remote Login URL.
- After successful login on your system, your system generates a JWT and submits it to the
/callbackjwt
endpoint via the hidden form field. - Benji Pays validates the JWT and either:
- If emailVerified: true - Logs the user directly into the customer portal
- If emailVerified: false/missing - Prompts for email verification first
Error Handling and User Experience
Benji Pays now provides improved error handling for JWT SSO with human-readable error codes:
JWT SSO Error Scenarios
JWT SSO developers will encounter these specific error codes when authentication issues occur:
- Account Not Found:
?error=account-not-found
The user's email address is not associated with any account in the system, or they don't have access to any companies with enabled portals. - Account Disabled:
?error=account-disabled
The user's account has been disabled by an administrator. - Email Verification Required:
?error=email-verification-required
The user needs to verify their email address through the SSO email verification process before accessing the portal.
Note: These are the primary error codes you'll encounter in JWT SSO implementations. Other error codes exist in the system but are specific to Auth0/OIDC SSO flows or internal processes that JWT developers won't encounter.
Handling Error Redirects
Your Remote Login URL should handle these error parameters to display appropriate messages:
// JWT SSO error handling example const urlParams = new URLSearchParams(window.location.search); const error = urlParams.get('error'); if (error) { let message = ''; switch(error) { case 'account-not-found': message = 'Account not found. Please contact support or check your email address.'; break; case 'account-disabled': message = 'Your account has been disabled. Please contact support for assistance.'; break; case 'email-verification-required': message = 'Please verify your email address to continue accessing the portal.'; break; default: message = 'Authentication error occurred. Please try again or contact support.'; } showErrorMessage(message); } function showErrorMessage(message) { // Example implementation - adapt to your UI framework const messageDiv = document.createElement('div'); messageDiv.className = 'alert alert-danger'; messageDiv.textContent = message; // Add to top of page document.body.insertBefore(messageDiv, document.body.firstChild); // Optional: Auto-hide after 5 seconds setTimeout(() => { messageDiv.remove(); }, 5000); }
Testing Your Integration
Test Scenarios
- Successful Login: Create a valid JWT and verify the user is logged in successfully
- Email Verification Skip: Use
emailVerified: true
and confirm no email verification step - Email Verification Required: Omit
emailVerified
and confirm email verification is required - Account Not Found: Test with an email not in the system and verify
?error=account-not-found
redirect - Account Disabled: Test with a disabled account and verify
?error=account-disabled
redirect - SSO Email Verification: Test email verification flow and verify
?error=email-verification-required
redirect - Invalid JWT: Test with expired/invalid tokens and verify appropriate error handling
Debugging
- Check JWT claims: Ensure all required claims are present and valid
- Verify signatures: Confirm JWT is signed with the correct CLIENTSECRET
- Monitor redirects: Check that error redirects include the expected error parameters
- Test token expiry: Ensure tokens are not expired when submitted
Security Notes
- Ensure the JWT includes all required claims, and the
exp
claim is no more than 5 minutes in the future. - The
iat
claim must not be more than 30 seconds in the past. - Use HTTPS for all communication to secure data in transit.
- Store the CLIENTSECRET securely and never expose it publicly.
- Email Verification Security: Only set
emailVerified: true
for emails you have actually verified in your system. - Error Handling: Implement proper error handling on your Remote Login URL to provide good user experience.
Migration Guide for Existing Integrations
If you have an existing JWT SSO integration:
- No changes required - Your current integration will continue to work exactly as before
- To add email verification: Simply add the
emailVerified
claim to your JWT payload when the user's email is verified - To improve error handling: Update your Remote Login URL to handle the new human-readable error parameters
Support and Troubleshooting
If you encounter issues:
- Validate your JWT: Use tools like jwt.io to decode and verify your token structure
- Check server logs: Look for JWT validation errors in your application logs
- Test incrementally: Start with basic authentication, then add email verification features
- Contact support: Include example JWT payload (without secrets) when requesting assistance
By following these steps, you can successfully configure and use JWT SSO with Benji Pays to provide a seamless, secure authentication experience for your users.
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article