{"id":20405610,"url":"https://github.com/nitrictech/node-jwt","last_synced_at":"2025-04-12T15:05:37.889Z","repository":{"id":46499814,"uuid":"404327781","full_name":"nitrictech/node-jwt","owner":"nitrictech","description":"Nitric Node.js SDK Middleware to validate JWTs and scope claims (permissions)","archived":false,"fork":false,"pushed_at":"2021-10-07T06:10:18.000Z","size":457,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"develop","last_synced_at":"2025-04-06T03:36:13.184Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nitrictech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-08T11:50:35.000Z","updated_at":"2021-12-13T07:35:40.000Z","dependencies_parsed_at":"2022-09-01T00:10:53.704Z","dependency_job_id":null,"html_url":"https://github.com/nitrictech/node-jwt","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrictech%2Fnode-jwt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrictech%2Fnode-jwt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrictech%2Fnode-jwt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitrictech%2Fnode-jwt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitrictech","download_url":"https://codeload.github.com/nitrictech/node-jwt/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586236,"owners_count":21128997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T05:12:08.333Z","updated_at":"2025-04-12T15:05:37.848Z","avatar_url":"https://github.com/nitrictech.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @nitric/middleware-jwt\n\nThis module provides Nitric Node-SDK HTTP Middleware for validating JWTs ([JSON Web Tokens](https://jwt.io)) through the [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken/) module, as well as middleware for validating the users permissions (scope) for RBAC. The decoded JWT payload is made available on the ctx object.\n\nThis set of middleware is particularly useful when integrating with external authentication providers such as [Auth0](https://auth0.com)\n\n## Install\n\n```bash\n$ npm install @nitric/middleware-jwt\n```\n\n## Usage\n\nBasic jwt validation and scope verification using an HS256 secret:\n\n```typescript\nimport { faas, createHandler } from '@nitric/sdk';\nimport { jwt, jwtScopes } from '@nitric/middleware-jwt';\n\nfaas\n  .http(\n    // compose a new handler that calls the middleware before your custom code\n    createHandler(\n      jwt({ secret: 'the-shared-secret', algorithms: ['HS256'] }),\n      jwtScopes(['create:orders']),\n      (ctx) =\u003e {\n        // access the decoded jwt in your code\n        console.log(ctx.user.firstName);\n      }\n    )\n  )\n  .start();\n```\n\n### Validating and Decoding JWTs\n\nThe decoded JWT payload is available on the context object `ctx`, by default it's below a new property `ctx.user`. The output property on the context object can be changed using the `outputProperty` option.\n\n\u003e The default behavior of the module is to extract the JWT from the `Authorization` header as an [OAuth2 Bearer token](https://oauth.net/2/bearer-tokens/).\n\n#### Required Parameters\nThe `algorithms` parameter is required to prevent potential downgrade attacks when providing third party libraries as **secrets**.\n\n:warning: **Do not mix symmetric and asymmetric (ie HS256/RS256) algorithms**: Mixing algorithms without further validation can potentially result in downgrade vulnerabilities.\n\n```javascript\njwt({\n  secret: 'the-shared-secret',\n  algorithms: ['HS256'],\n  //algorithms: ['RS256']\n})\n```\n\n#### Additional Options\n\nYou can specify audience and/or issuer as well, which is highly recommended for security purposes:\n\n```typescript\njwt({\n  secret: 'the-shared-secret',\n  algorithms: ['HS256'],\n  verifyOptions: {\n    audience: 'http://myapi/protected',\n    issuer: 'http://issuer',\n  }\n})\n```\n\n\u003e If the JWT has an expiration (`exp`), it will be checked automatically.\n\nIf you are using a base64 URL-encoded secret, pass a `Buffer` with `base64` encoding as the secret instead of a string:\n\n```typescript\njwt({\n  secret: Buffer.from('the-shared-secret', 'base64'),\n  algorithms: ['RS256'],\n})\n```\n\nThis module also support tokens signed with public/private key pairs. Instead of a secret, you can specify a Buffer with the public key\n\n```typescript\nconst publicKey = fs.readFileSync('/path/to/public.pub');\njwt({ secret: publicKey, algorithms: ['RS256'] });\n```\n\n#### Retrieving the Decoded Payload\n\nBy default, the decoded token is attached to `ctx.user` but can be configured with the `outputProperty` option.\n\n```javascript\n// attach to ctx.auth using outputProperty\njwt({ secret: publicKey, algorithms: ['RS256'], outputProperty: 'auth' });\n```\n\n\u003e `outputProperty` uses [lodash.set](https://lodash.com/docs/4.17.2#set) and will accept nested property paths.\n\n#### Customizing Token Location\n\nA custom function for extracting the token from a the context can be specified with\nthe `getToken` option. This is useful if you need to pass the token through a\nquery parameter or a cookie. You can throw an error in this function and it will\nbe handled by the middleware, resulting in a 401 Unauthorize response.\n\n```typescript\nimport { faas, createHandler } from '@nitric/sdk';\nimport { jwt } from '@nitric/middleware-jwt';\n\nfaas\n  .http(\n    createHandler(\n      jwt({\n        secret: 'the-shared-secret',\n        algorithms: ['HS256'],\n        getToken: ({req}) =\u003e {\n          if (req.headers.authorization \u0026\u0026 req.headers.authorization.split(' ')[0] === 'Bearer') {\n              return req.headers.authorization.split(' ')[1];\n          } else if (req.query \u0026\u0026 req.query.token) {\n            return req.query.token;\n          }\n          return null;\n        }\n      }),\n      yourHandler,\n    )\n  )\n  .start();\n```\n\n#### Multi-tenancy\n\nIf you are developing an application in which the secret used to sign tokens is not static, you can provide a function as the `secret` parameter. The function has the signature: `function(ctx, header, payload)` and can be sync or async (return a Promise):\n* `ctx` (`HttpContext`) - The Nitric SDK HttpContext object, containing keys for request `ctx.req` and response `ctx.res`.\n* `header` (`Object`) - An object with the JWT header.\n* `payload` (`Object`) - An object with the JWT claims.\nFor example, if the secret varies based on the [JWT issuer](http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#issDef):\n\n```typescript\nimport { faas, createHandler } from '@nitric/sdk';\nimport { jwt, jwtScopes } from '@nitric/middleware-jwt';\nimport data from './data';\nimport utils from './utils';\n\nconst getSecret = async (ctx, header, payload) =\u003e {\n  const issuer = payload.iss;\n  const tenant = await data.getTenantByIdentifier(issuer);\n  if (!tenant) {\n    throw new Error('missing_secret');\n  }\n\n  return utils.decrypt(tenant.secret);\n};\n\nfaas\n  .http(\n    createHandler(\n      jwt({ secret: getSecret, algorithms: ['HS256'] }),\n      yourHandler,\n    )\n  )\n  .start();\n```\n\n#### Revoked tokens\nIt 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 `function(ctx, payload)`, it should return a boolean and can be sync or async:\n* `ctx` (`HttpContext`) - The Nitric SDK HttpContext object, containing keys for request `ctx.req` and response `ctx.res`.\n* `payload` (`Object`) - An object with the JWT claims.\n\nFor example, if the `(iss, jti)` claim pair is used to identify a JWT:\n```typescript\nimport { faas, createHandler } from '@nitric/sdk';\nimport { jwt, jwtScopes } from '@nitric/middleware-jwt';\nimport utils from './utils';\n\nconst isRevoked = async (ctx, payload) =\u003e {\n  const issuer = payload.iss;\n  const tokenId = payload.jti;\n\n  // your custom method of querying if the token is revoked.\n  return await utils.isRevokedToken(issuer, tokenId);\n};\n\nfaas\n  .http(\n    createHandler(\n      jwt({\n        secret: 'the-shared-secret',\n        algorithms: ['HS256'],\n        isRevoked\n      }),\n      yourHandler,\n    )\n  )\n  .start();\n```\n\n#### Error handling\n\nThe default behavior is to return a 401 unauthorized response. You can decorate this middleware if custom behavior is needed.\n\n### Verifying Permissions (Scopes)\n\nOnce a JWT has been decoded into the `ctx` using the `jwt` middleware, the `jwtScopes` middleware can be used to verify that the jwt payload contained the required permissions (scope) to make the request.\n\nPass the list of required scopes as the first parameter to `jwtScopes`. When multiple scopes are provided by default they'll all be required.\n\n```typescript\njwt(['read:user', 'write:user']);\n\n// This user will have access\nvar authorizedUser = {\n  scope: 'read:user write:user'\n};\n\n// This user will NOT have access\nvar unauthorizedUser = {\n  scope: 'read:user'\n};\n```\n\nInstead of requiring all scopes, you can specify that *at least one* of the specified scopes is required.\n\n```typescript\njwt(['read:user', 'write:user'], {allRequired: false});\n\n// Both of these users will have access\nvar authorizedUserOne = {\n  scope: 'read:user write:user'\n};\n\nvar authorizedUserTwo = {\n  scope: 'read:user'\n};\n```\n\nBy default the previously decoded JWT must have contained a `scope` claim, which contained a string of space-separated permissions or an array of strings.\n\n\u003e This is the standard for [OAuth Bearer Tokens](https://oauth.net/2/bearer-tokens/)\n\nFor example:\n\n```typescript\n// String:\n\"write:users read:users\"\n\n// Array:\n[\"write:users\", \"read:users\"]\n```\n\n#### Customizing scope location\n\nIf the user's scopes are stored elsewhere in the ctx object, you can specify a custom path to the scopes string or array below the `ctx`.\n\n\u003e `scopesProperty` uses [lodash.get](https://lodash.com/docs/4.17.2#get) and will accept nested property paths.\n\n```typescript\n// This will resolve to ctx.auth.permissions\njwt('read:user', {scopesProperty: \"auth.permissions\"});\n```\n\n#### Customizing the scope string separator\n\nIf the scope claim contains a string that uses a separator other than a space between scopes, you can specify a custom separator.\n\n\u003e If the scope claim contains an array, the scopeSeparator property is ignored.\n\n```typescript\n// This will resolve to ctx.auth.permissions\njwt('read:user', {scopeSeparator: \"|\"});\n\n// This scope claim would now be parsed\n{\n  scope: \"read:user|write:user\",\n}\n```\n\n### Additional Notes\n\n\u003e This module was adapted from code authored by the Auth0 team in their ExpressJS Middleware projects [express-jwt](https://github.com/auth0/express-jwt) and [express-jwt-authz](https://github.com/auth0/express-jwt-authz).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrictech%2Fnode-jwt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitrictech%2Fnode-jwt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrictech%2Fnode-jwt/lists"}