@immersa/auth0-jwt-validator v1.0.2
Auth0 JWT Validator
Authentication tools for Node.js that validates JWT Bearer Access Tokens, scopes and permissions using auth0.
- Install
- Getting started
- API Documentation
- Examples
- Error Handling
- What is Auth0?
- License
- Contributing
- Copyright
Install
This package supports Node >= 12
npm install @immersa/auth0-jwt-validator
Getting started
The library is agnostic to any NodeJs framework, so we need to use it within custom middlewares since every framework handles the request, response and next in different ways.
With this basic configuration, your api will require a valid Access Token JWT bearer token for all routes.
API Documentation
Complete documentation can be found here.
- getToken - Validate and get the token from the header request and will return a 401 if a valid JWT bearer token in the request is not provided or has an invalid format.
- JwtVerifier - Class that verifies the token and will return a 401 if a valid JWT bearer token is not provided. Internally will use the
jwksUri
to get the public keys form Auth Server Metadata for the verification. - requiredPermissions - Check a token's permissions claim to include 1 or more permissions, raises a 403
insufficient_permission
error if the value of the scope claim does not include all the given permissions. - requiredScopes - Check a token's scope claim to include a number of given scopes, raises a 403
insufficient_scope
error if the value of the scope claim does not include all the given scopes. - claimEquals - Check a token's claim to be equal a given JSONPrimitive (string, number, boolean or null) raises a 401
invalid_token
error if the value of the claim does not match. - claimIncludes - Check a token's claim to include a number of given JSONPrimitives (string, number, boolean or null) raises a 401
invalid_token
error if the value of the claim does not include all the given values. - claimCheck - Check the token's claims using a custom method(predicate) that receives the JWT Payload and should return
true
if the token is valid. Raises a 401invalid_token
error if the function returnsfalse
.
Examples
ExpressJs
auth-middleware.ts
const { jwtVerifier, getToken } = require('auth0-jwt-validator')
export const auth = (opts: JwtVerifierOptions = {}): Handler => {
const verifier = new jwtVerifier(opts)
return async (req: Request, res: Response, next: NextFunction) => {
try {
const jwt = getToken(req.headers)
req.auth = await verifier.verify(jwt)
next()
} catch (e) {
next(e)
}
}
}
route config
// Config app to use the AuthMIddleware for all the requests
{
const {auth} = require('my-middleware-folder/auth-middleware')
...
app.use(
auth({
issuer: 'https://YOUR_ISSUER_DOMAIN',
audience: 'https://my-api.com',
jwksUri: 'https://issuer.example.com/.well-known/jwks.json',
})
)
}
permissions-middleware.ts
const { requiredPermissions as _requiredScopes, JWTPayload, RequiredScopes, Permission } = require('auth0-jwt-validator')
// Create a handler as a High order function to be able to use it as a middleware directly in any route
const toHandler =
(fn: (payload?: JWTPayload) => void): Handler =>
(req, res, next) => {
try {
fn(req.auth?.payload);
next();
} catch (e) {
next(e);
}
};
export const requiredPermissions: RequiredScopes<Handler> = (...args) =>
toHandler(_requiredScopes(...args));
Handler workaround works for the rest of functions:
claimIncludes
,claimCheck
,claimEquals
andrequiredScopes
Route config
const {requiredPermissions, Permission} = require('my-middleware-folder/permissions-middleware')
// Use enum for known permissions
{
app.get('/admin/edit', requiredPermissions(Permission.Enhanced),
(req, res) => { ... });
}
custom-validation-middleware.ts
const { claimCheck as _claimCheck } = require('auth0-jwt-validator')
// Use the previous Handler function
export const claimCheck: RequiredScopes<Handler> = (...args) =>
toHandler(_claimCheck(...args));
Route config
const {claimCheck} = require('my-middleware-folder/custom-validation-middleware')
...
app.get(
'/api/admin/edit',
claimCheck(({ isAdmin, roles }) => isAdmin && roles.includes('editor')),
(req, res, next) => {
// ...
}
)
AdonisJs
Middleware/AuthRequest.ts
import { getToken, JwtVerifier } from 'auth0-jwt-validator'
export default class AuthRequest {
public async handle(ctx: HttpContextContract, next: () => Promise<void>) {
const token = getToken(ctx.request.headers())
const verifier = new JwtVerifier({
issuer: 'https://YOUR_ISSUER_DOMAIN',
audience: 'https://my-api.com',
jwksUri: 'https://issuer.example.com/.well-known/jwks.json',
})
const payload = await verifier.verify(token)
ctx.auth = { token, payload }
await next()
}
}
Don't forget to inform Typescript about the new props in context. Check how to do it here
kernel.ts
Server.middleware.register([() => import('App/Middleware/AuthRequest')])
Middleware/PermissionsRequest.ts
import { requiredPermissions } from 'auth0-jwt-validator'
export default class PermissionsRequest {
public async handle(
ctx: HttpContextContract,
next: () => Promise<void>,
permissions: string[] | string
) {
const { payload } = ctx.auth || {}
requiredPermissions(permissions)(payload)
await next()
}
}
kernel.ts
Server.middleware.registerNamed({
permissions: () => import('App/Middleware/PermissionsRequest'),
})
Route
import { Permission } from 'auth0-jwt-validator'
Route.get('dashboard', 'UserController.dashboard').middleware(
`permissions:${Permission.Enhanced}`
)
Error Handling
This SDK raises errors with err.status
and err.headers
according to rfc6750. So for error handling consider the following premises:
res.statusCode
set fromerr.status
res.statusMessage
set according to the status code.- The body will be the HTML of the status code message when in production environment, otherwise will be
err.stack
. - Any headers specified in an
err.headers
object.
The error_description
in the WWW-Authenticate
header will contain useful information about the error, which you may not want to disclose in Production.
What is Auth0?
Auth0 helps you to easily:
- Implement authentication with multiple identity providers, including social (e.g., Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter, etc), or enterprise (e.g., Windows Azure AD, Google Apps, Active Directory, ADFS, SAML, etc.)
- Log in users with username/password databases, passwordless, or multi-factor authentication
- Link multiple user accounts together
- Generate signed JSON Web Tokens to authorize your API calls and flow the user identity securely
- Access demographics and analytics detailing how, when, and where users are logging in
- Enrich user profiles from other data sources using customizable JavaScript rules
License
This project is licensed under the MIT license. See the LICENSE file for more info.
Contributing
Commits should follow the next format:
type
(scope
): message
Example:
test(k2-1234): Add pending tests
Type
Must be one of the following:
build
: Changes that affect the build system or external dependencies (example scopes: npm)
ci
: Changes to our CI configuration files and scripts (examples: GitHub Actions, Hooks)
docs
: Documentation only changes
feat
: A new feature
fix
: A bug fix
perf
: A code change that improves performance
refactor
: A code change that neither fixes a bug nor adds a feature
test
: Adding missing tests or correcting existing tests
IMPORTANT:
feat
,fix
andperf
are types that always trigger a new release.
Scope
Must be the ticket/task Id
Copyright
This package is a custom implementation of: