{"id":26942427,"url":"https://github.com/connectedcars/node-jwtutils","last_synced_at":"2025-04-02T16:49:05.039Z","repository":{"id":25037811,"uuid":"100960563","full_name":"connectedcars/node-jwtutils","owner":"connectedcars","description":"Zero dependency JWT encoding and decoding for Node","archived":false,"fork":false,"pushed_at":"2024-02-28T08:38:41.000Z","size":993,"stargazers_count":2,"open_issues_count":21,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-25T11:02:26.586Z","etag":null,"topics":["backend","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/connectedcars.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-08-21T14:31:45.000Z","updated_at":"2023-01-31T16:52:08.000Z","dependencies_parsed_at":"2024-02-28T09:37:37.372Z","dependency_job_id":"ebc10c4b-2c08-4b79-9a39-133dd8065ee4","html_url":"https://github.com/connectedcars/node-jwtutils","commit_stats":{"total_commits":162,"total_committers":9,"mean_commits":18.0,"dds":"0.22839506172839508","last_synced_commit":"2801a8fd77200f693de2e8789b2820f0163a56c8"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectedcars%2Fnode-jwtutils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectedcars%2Fnode-jwtutils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectedcars%2Fnode-jwtutils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectedcars%2Fnode-jwtutils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/connectedcars","download_url":"https://codeload.github.com/connectedcars/node-jwtutils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246855476,"owners_count":20844936,"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":["backend","nodejs"],"created_at":"2025-04-02T16:49:04.467Z","updated_at":"2025-04-02T16:49:05.023Z","avatar_url":"https://github.com/connectedcars.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-jwtutils\n\n[![Build Status](https://travis-ci.org/connectedcars/node-jwtutils.svg?branch=master)](https://travis-ci.org/connectedcars/node-jwtutils)\n[![Coverage Status](https://coveralls.io/repos/github/connectedcars/node-jwtutils/badge.svg?branch=master)](https://coveralls.io/github/connectedcars/node-jwtutils?branch=master)\n\nZero dependency JWT encoding and decoding for Node.\n\nFeatures:\n\n* Encode and decode any JWT tokens\n* Supported asymmetric algorithmes (RS256, RS384, RS512, ES256, ES384 and ES512)\n* Supported symmetric algorithmes (HS256, HS384 and HS512)\n* Support for multiple issuers and keys per issuer.\n* Import keys from JWK endpoints\n* Easy service authentication for Google and Github\n* Express middleware to validate JWT's\n\n## Background\n\nMost other JWT implementations tend be complex and have a large array of\ndependencies because they implement the seldom used JOSE standard.\nThis often makes the whole JWT encoding/decoding complicated and hard to\nunderstand, something it really should not be.\n\nSo the focus of this module has been to make a simple, secure, fast and\nflexible set of utility methods to work with JWT's. The code itself is also\neasy to understand and less than 200 lines of code, making it much easier to\nsecurity audit the code.\n\nAlso note doing your own crypto is a bad idea so this module only deals with\nthe encoding/decoding of the JWT, the underlaying crypto operations are done\nby Node's build-in crypto api that uses openssl.\n\nWhile symmetric algorithms are supported for legacy integrations, they are\nnot advisable for production use.\n\n## Samples\n\n* [Integrate with Google Identity Platform](sample/googleoauth2v2/README.md)\n\n## Basic usage\n\n``` javascript\nconst { JwtUtils, JwtVerifyError } = require('@connectedcars/jwtutils')\n\nconst unixNow = Math.floor(Date.now() / 1000)\n\nlet jwtHeader = {\n  typ: 'JWT',\n  alg: 'RS256',\n  kid: '1'\n}\n\nlet jwtBody = {\n  aud: 'https://api.domain.tld',\n  iss: 'https://jwt.io/',\n  sub: 'subject@domain.tld',\n  iat: unixNow,\n  exp: unixNow + 600,\n  scope: ['http://stuff', 'http://stuff2']\n}\n\n// Don't use this key for anything but testing as this is the key from jwt.io\nconst pemEncodedPrivateKey =\n  '-----BEGIN RSA PRIVATE KEY-----\\n' +\n  'MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw\\n' +\n  '33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW\\n' +\n  '+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB\\n' +\n  'AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS\\n' +\n  '3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp\\n' +\n  'uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE\\n' +\n  '2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0\\n' +\n  'GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K\\n' +\n  'Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY\\n' +\n  '6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5\\n' +\n  'fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523\\n' +\n  'Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP\\n' +\n  'FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==\\n' +\n  '-----END RSA PRIVATE KEY-----'\n\n// let jwt = JwtUtils.encode(pemEncodedPrivateKey, jwtHeader, jwtBody, privateKeyPassword)\nlet jwt = JwtUtils.encode(pemEncodedPrivateKey, jwtHeader, jwtBody)\n\n// Don't use this key for anything but testing as this is the key from jwt.io\nconst publicKey =\n  '-----BEGIN PUBLIC KEY-----\\n' +\n  'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\\n' +\n  'UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\\n' +\n  'HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\\n' +\n  'o2kQ+X5xK9cipRgEKwIDAQAB\\n' +\n  '-----END PUBLIC KEY-----'\n\nconst allowedAudinces = ['https://api.domain.tld']\n\nconst pubKeys = {\n  'https://jwt.io/': {\n    '1@RS256': publicKey,\n    'default@RS256': publicKey // Will default to this key if the header does not have a kid\n  }\n}\n\ntry {\n  let decodedJwtBody = JwtUtils.decode(jwt, pubKeys, allowedAudinces)\n} catch (e) {\n  if (e instanceof JwtVerifyError) {\n    // Can be returned to user\n  } else {\n    // Should not be returned to user\n    console.error(e)\n  }\n}\n```\n\n## Usage of express middleware\n\n``` javascript\nconst express = require('express')\nconst { JwtAuthMiddleware, JwtVerifyError } = require('@connectedcars/jwtutils')\n\n// Configuration\nconst audiences = ['https://api.domain.tld']\nconst pubKeys = {\n  'https://jwt.io/': {\n    '1@RS256': publicKey // Fx. use key from before\n  },\n  'https://jwt.io/custom': { // Overwrite default validation for this issuer\n    '1@RS256': { // Same options can also be used directly with decode\n      publicKey: publicKey,\n      expiresMax: 3600, // Don't allow token that has a lifetime over 1 hour\n      expiresSkew: 600, // Allow tokens that expired up to 10 minutes ago\n      nbfIatSkew: 300, // Allow tokens that has nbf or iat in the future by up to 5 minutes\n    }\n  }\n}\n\nconst app = express()\n\n// Register the middleware\napp.use(JwtAuthMiddleware(pubKeys, audiences, user =\u003e { // Also supports Promises and async\n  if (user.issuer === 'https://jwt.io/') {\n    if (!user.subject.match(/^[^@]+@domain\\.tld$/)) {\n      throw new JwtVerifyError('Issuer https://jwt.io/ only allowed to have subject ending in @domain.tld')\n    }\n  }\n}))\n\n// Register an error handler to return 401 errors\napp.use((err, req, res, next) =\u003e {\n  if (err instanceof JwtVerifyError) {\n    if (err.innerError) {\n      console.error(`Failed with: ${err.innerError.message}`)\n    }\n    res.status(401).send(err.message)\n  } else {\n    res.status(500).send('Unknown error')\n  }\n})\n\napp.get('/', (req, res) =\u003e {\n  res.send(`Hello ${req.user.subject}`)\n})\napp.listen(3000, () =\u003e {\n  console.log('Example app listening on port 3000!')\n})\n```\n\n### Integration with 3rd parties\n\nGoogle Identity platform:\n\n``` javascript\nconst { PubkeysHelper } = require('@connectedcars/jwtutils')\n\n// Fetch with Google's public keys every hour\nconst applyGoogleKeys = (pubKeys) =\u003e {\n  PubkeysHelper.fetchJwkKeys('https://www.googleapis.com/oauth2/v3/certs')\n    .then(keys =\u003e {\n      pubKeys['https://accounts.google.com'] = keys\n    })\n    .catch(e =\u003e {\n      // Do some error handling\n      console.log(e)\n    })\n}\n\napplyGoogleKeys(pubKeys)\nsetInterval(() =\u003e {\n  applyGoogleKeys(pubKeys)\n}, 60 * 60 * 1000)\n```\n\n## Usage of service authentication (Google and Github)\n\n``` javascript\nconst { JwtServiceAuth } = require('./index')\nconst fs = require('fs')\nconst r2 = require('r2')\n\n// Wrap your favorite http library\nlet httpRequestHandler = async (method, url, headers, body) =\u003e { // Fx. POST, http://domain.tld, {}, \"...\"\n  // Do http request\n  let httpRespone = await r2[method.toLowerCase()](url, { headers, body }).response\n  let data = await httpResponse.arrayBuffer()\n  return {\n    statusCode: httpResponse.status,\n    data: data,\n    headers: httpResponse.headers\n  }\n})\n\nlet jwtServiceAuth = new JwtServiceAuth(httpRequestHandler) // Or use the built-in default\n\nlet gitHubAppPrivateKey = fs.readFileSync(\"user-appname.2017-01-01.private-key.pem\", 'utf8')\nlet googleServiceAccountKeyfile = fs.readFileSync(\"user-serviceaccount-12345678.json\", 'utf8')\n\nasync function getAccessTokens() {\n  let githubAppToken = await = jwtServiceAuth.getGithubAccessToken(gitHubAppPrivateKey, 1, 1)\n  let googleToken = await jwtServiceAuth.getGoogleAccessToken(googleServiceAccountKeyfile)\n}\n```\n\n### Documentation\n\n* Github App: https://developer.github.com/apps/building-github-apps/authentication-options-for-github-apps/\n* Google Service Account: https://developers.google.com/identity/protocols/OAuth2ServiceAccount\n\n## Generate own keypair\n\nGenerate private RSA key:\n\n``` bash\n# Here the key is encrypted with aes256\nopenssl genrsa -aes256 -out private.pem 2048\n```\n\nGenerate public key from private key:\n\n``` bash\nopenssl rsa -in private.pem -outform PEM -pubout -out public.pem\n```\n\n## Command line helper utils\n\n*NOTE: Does not support nested JSON*\n\nLoad private key:\n\n``` bash\njwtencode private.pem\n```\n\nCopy/paste to stdin (Ctrl-D to end), the password line is only needed if the private key is encrypted:\n\n``` text\npassword password-for-private-key\n{\n  \"alg\": \"RS256\",\n  \"typ\": \"JWT\",\n  \"kid\": \"1\"\n}\n{\n  \"iss\": \"jwt.io\",\n  \"aud\": \"https://api.domain.tld\",\n  \"sub\": \"subject@domain.tld\",\n  \"iat\": 1504292127,\n  \"nbf\": 1504292127,\n  \"exp\": 1598986470\n}\n````\n\n``` bash\njwtdecode public.pem 1 RS256 https://jwt.io localhost\n```\n\nCopy/paste to stdin (Ctrl-D to end):\n\n``` text\neyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ.eyJpc3MiOiJodHRwczovL2p3dC5pbyIsImF1ZCI6ImxvY2FsaG9zdCIsInN1YiI6InN1YmplY3RAZG9tYWluLnRsZCIsImlhdCI6MTUwNDI5MjEyNywibmJmIjoxNTA0MjkyMTI3LCJleHAiOjE1OTg5ODY0NzB9.0L5AWwUF3EleBqnQ6V0Lqa36jCccP4A7cAFHHIY1b-oE7pxCoFr8gnAOrlc16N0WUPI6O17JT79kQIPR-LjFm-BgBycBw4eEFYb8z7iXA-zqgQz4ajZXlIljJtJUBbTupbnzEiBKjEFnTxYqb-vUm-TDwTMPaYzBxqqfOrrvKlw\n````\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectedcars%2Fnode-jwtutils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconnectedcars%2Fnode-jwtutils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectedcars%2Fnode-jwtutils/lists"}