koa-jwt2
Version:
JWT authentication middleware.
232 lines (175 loc) • 6.26 kB
Markdown
[](http://travis-ci.org/okoala/koa-jwt2)
Koa middleware that validates JsonWebTokens and sets `ctx.state.user`.
This module lets you authenticate HTTP requests using JWT tokens in your Node.js
applications. JWTs are typically used to protect API endpoints, and are
often issued using OpenID Connect.
$ npm install koa-jwt2 --save
The JWT authentication middleware authenticates callers using a JWT.
If the token is valid, `ctx.state.user` will be set with the JSON object decoded
to be used by later middleware for authorization and access control.
For example,
```javascript
var jwt = require("koa-jwt2");
app.get("/protected", jwt({ secret: "shhhhhhared-secret" }), async function(
ctx
) {
if (!ctx.state.user.admin) return (ctx.status = 401);
ctx.status = 200;
});
```
You can specify audience and/or issuer as well:
```javascript
jwt({
secret: "shhhhhhared-secret",
audience: "http://myapi/protected",
issuer: "http://issuer"
});
```
> If the JWT has an expiration (`exp`), it will be checked.
If you are using a base64 URL-encoded secret, pass a `Buffer` with `base64` encoding as the secret instead of a string:
```javascript
jwt({ secret: new Buffer("shhhhhhared-secret", "base64") });
```
Optionally you can make some paths unprotected as follows:
```javascript
app.use(jwt({ secret: "shhhhhhared-secret" }).unless({ path: ["/token"] }));
```
This is especially useful when applying to multiple routes. In the example above, `path` can be a string, a regexp, or an array of any of those.
> For more details on the `.unless` syntax including additional options, please see [koa-unless](https://github.com/Foxandxss/koa-unless).
This module also support tokens signed with public/private key pairs. Instead of a secret, you can specify a Buffer with the public key
```javascript
var publicKey = fs.readFileSync("/path/to/public.pub");
jwt({ secret: publicKey });
```
By default, the decoded token is attached to `ctx.state.user` but can be configured with the `property` option.
```javascript
jwt({ secret: publicKey, property: "auth" });
```
A custom function for extracting the token from a request can be specified with
the `getToken` option. This is useful if you need to pass the token through a
query parameter or a cookie. You can throw an error in this function and it will
be handled by `koa-jwt2`.
```javascript
app.use(
jwt({
secret: "hello world !",
credentialsRequired: false,
getToken: function fromHeaderOrQuerystring(ctx) {
if (
ctx.headers.authorization &&
ctx.headers.authorization.split(" ")[0] === "Bearer"
) {
return ctx.headers.authorization.split(" ")[1];
} else if (ctx.query && ctx.query.token) {
return ctx.query.token;
}
return null;
}
})
);
```
If you are developing an application in which the secret used to sign tokens is not static, you can provide a async function as the `secret` parameter. The function has the signature: `async function(ctx, payload)`:
* `ctx` (`Object`) - The koa `ctx` object.
* `payload` (`Object`) - An object with the JWT claims.
need to return a secret string or promise to use to verify the JWT.
For example, if the secret varies based on the [JWT issuer](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#issDef):
```javascript
const jwt = require("koa-jwt2");
const data = require("./data");
const utilities = require("./utilities");
const secretAsync = async function(ctx, payload) {
const issuer = payload.iss;
return new Promise((resolve, reject) => {
data.getTenantByIdentifier(issuer, function(err, tenant) {
if (err) {
return reject(err);
}
if (!tenant) {
reject(new Error("missing_secret"));
}
const secret = utilities.decrypt(tenant.secret);
resolve(secret);
});
});
};
app.get("/protected", jwt({ secret: secretCallback }), async function(ctx) {
if (!ctx.state.user.admin) {
ctx.throw(401);
}
ctx.status = 200;
ctx.body = "";
});
```
It is possible that some tokens will need to be revoked so they cannot be used any longer. You can provide a function as the `isRevoked` option. The signature of the function is `async function(ctx, payload)`:
* `ctx` (`Object`) - The koa `context` object.
* `payload` (`Object`) - An object with the JWT claims.
For example, if the `(iss, jti)` claim pair is used to identify a JWT:
```javascript
const jwt = require("koa-jwt2");
const data = require("./data");
const utilities = require("./utilities");
const isRevokedAsync = function(req, payload, done) {
const issuer = payload.iss;
const tokenId = payload.jti;
return new Promise((resolve, reject) => {
data.getRevokedToken(issuer, tokenId, function(err, token) {
if (err) {
return reject(err);
}
resolve(!!token);
});
});
};
app.get(
"/protected",
jwt({
secret: "shhhhhhared-secret",
isRevoked: isRevokedAsync
}),
async function(ctx) {
if (!ctx.state.user.admin) {
ctx.throw(401);
}
ctx.status = 200;
ctx.body = "";
}
);
```
The default behavior is to throw an error when the token is invalid, so you can add your custom logic to manage unauthorized access as follows:
```javascript
app.use(async function(ctx, next) {
try {
await next();
} catch (err) {
if (err.name === "UnauthorizedError") {
ctx.status = 401;
ctx.body = "invalid token...";
}
}
});
```
You might want to use this module to identify registered users while still providing access to unregistered users. You
can do this by using the option _credentialsRequired_:
```javascript
app.use(
jwt({
secret: "hello world !",
credentialsRequired: false
})
);
```
* [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) — JSON Web Token sign and verification
$ npm install
$ npm test
Check them out [here](https://github.com/okoala/koa-jwt2/graphs/contributors)
This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.