Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
OAuthService
✓ import { OAuthService } from 'sumor'
✗ const { OAuthService } = require('sumor')
Primary class for server-side interaction with the OAuth provider. The package is TypeScript-first, favoring ESM imports.
loadJwtUserMiddleware
✓ import { loadJwtUserMiddleware } from 'sumor'
✗ import loadJwtUserMiddleware from 'sumor/loadJwtUserMiddleware'
Express middleware for validating JWTs and attaching user info to `req.jwtUser`.
oauthRoutes
✓ import { oauthRoutes } from 'sumor'
✗ import * as oauthRoutes from 'sumor/routes'
Pre-configured Express Router for OAuth callback, token refresh, and logout endpoints.
refreshToken
✓ import { refreshToken } from 'sumor/web'
✗ import { refreshToken } from 'sumor'
Client-side function from the browser SDK to refresh authentication tokens.
login
✓ import { login } from 'sumor/web'
✗ import { login } from 'sumor'
Client-side function from the browser SDK to initiate the OAuth login flow.
Initializes an Express application with Sumor's OAuth routes and JWT user middleware, demonstrating basic server setup for authentication, authorization, and permission synchronization with an OAuth provider.
import express from 'express';
import { OAuthService, loadJwtUserMiddleware, oauthRoutes } from 'sumor';
const app = express();
// Configure OAuth environment variables (example, replace with actual values)
process.env.SUMOR_OAUTH_CLIENT_ID = process.env.OAUTH_CLIENT_ID ?? 'your-client-id';
process.env.SUMOR_OAUTH_CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET ?? 'your-client-secret';
process.env.SUMOR_OAUTH_AUTH_URL = process.env.OAUTH_AUTH_URL ?? 'https://your-oauth-provider.com/authorize';
process.env.SUMOR_OAUTH_TOKEN_URL = process.env.OAUTH_TOKEN_URL ?? 'https://your-oauth-provider.com/token';
process.env.SUMOR_OAUTH_REDIRECT_URI = process.env.OAUTH_REDIRECT_URI ?? 'http://localhost:3000/api/oauth/callback';
process.env.SUMOR_OAUTH_JWKS_URL = process.env.OAUTH_JWKS_URL ?? 'https://your-oauth-provider.com/.well-known/jwks.json';
// Create an instance of OAuthService for permission synchronization
const oauthService = new OAuthService();
// Register pre-configured OAuth routes BEFORE the JWT middleware
// This ensures the callback endpoint does not require authentication.
app.use('/api/oauth', oauthRoutes);
// JWT middleware: validates tokens and injects req.jwtUser for subsequent routes
app.use(loadJwtUserMiddleware);
// Example: Synchronize permissions on application startup
// In a production environment, this might be done once during deployment or on a schedule.
(async () => {
try {
await oauthService.updatePermissions({
permissions: ['posts:view', 'posts:create', 'users:manage'],
permissionLabels: [
{ module: 'posts', zh: '文章管理', en: 'Posts Management' },
{ module: 'users', zh: '用户管理', en: 'User Management' }
]
});
console.log('Permissions synchronized successfully.');
} catch (error) {
console.error('Failed to synchronize permissions:', error);
}
})();
// Your protected API routes
app.get('/api/profile', (req, res) => {
// req.jwtUser is available after loadJwtUserMiddleware
if (!req.jwtUser) {
return res.status(401).send('Unauthorized');
}
const { userId, roles, permissions } = req.jwtUser;
res.json({
message: 'Welcome to your profile!',
userId,
roles: roles?.split(',') ?? [],
permissions: permissions?.split(',') ?? []
});
});
app.get('/api/admin', (req, res) => {
if (!req.jwtUser || !(req.jwtUser.roles?.includes('admin') || req.jwtUser.permissions?.includes('users:manage'))) {
return res.status(403).send('Forbidden');
}
res.send('Admin content!');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
Errors
Common errors & fixes
TypeError: Cannot read properties of undefined (reading 'userId') OR TypeError: req.jwtUser is undefined
The `loadJwtUserMiddleware` was not applied, or it was applied after the route attempting to access `req.jwtUser`.
fixEnsure `app.use(loadJwtUserMiddleware)` is registered globally or before any protected routes that require `req.jwtUser`.
Error: Missing SUMOR_OAUTH_CLIENT_ID environment variable
The `OAuthService` or related components failed to initialize due to missing OAuth configuration in environment variables.
fixSet all necessary `SUMOR_OAUTH_*` environment variables (e.g., CLIENT_ID, CLIENT_SECRET, AUTH_URL, TOKEN_URL, REDIRECT_URI, JWKS_URL).
401 Unauthorized / Invalid Token
The JWT token in the request was missing, expired, invalid, or failed validation by `loadJwtUserMiddleware`.
fixCheck the client-side token acquisition and refresh logic. Verify the `SUMOR_OAUTH_JWKS_URL` is correct and accessible for JWT signature validation. Ensure the token is properly sent in the `Authorization` header.
403 Forbidden
The authenticated user (`req.jwtUser`) does not possess the required roles or permissions for the accessed route.
fixVerify the user's assigned roles/permissions in the OAuth provider. Ensure permission synchronization (`oauthService.updatePermissions`) is up-to-date. Implement proper permission checking logic in your routes using `req.jwtUser.roles` or `req.jwtUser.permissions`.
Audit
Dependencies
expressrequiredRequired as a peer dependency for the server-side middleware and routing.