{"id":20195860,"url":"https://github.com/villedemontreal/authentication-nodejs-lib","last_synced_at":"2025-04-10T10:14:13.744Z","repository":{"id":38043765,"uuid":"323442377","full_name":"VilledeMontreal/authentication-nodejs-lib","owner":"VilledeMontreal","description":"This library handles transparent authentication of backend to backend API calls, using the OpenID Connect protocol.","archived":false,"fork":false,"pushed_at":"2024-09-21T15:46:15.000Z","size":2921,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2025-04-09T15:06:14.528Z","etag":null,"topics":["auth","axios","clientcredentials","hacktoberfest","http-client","nodejs","oauth2","oidc","request","superagent"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/VilledeMontreal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-21T20:36:45.000Z","updated_at":"2024-10-29T14:16:04.000Z","dependencies_parsed_at":"2023-12-10T01:29:54.646Z","dependency_job_id":"4c040d83-f8a8-49b6-95ac-8af01273c619","html_url":"https://github.com/VilledeMontreal/authentication-nodejs-lib","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":"VilledeMontreal/repository-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VilledeMontreal%2Fauthentication-nodejs-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VilledeMontreal%2Fauthentication-nodejs-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VilledeMontreal%2Fauthentication-nodejs-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VilledeMontreal%2Fauthentication-nodejs-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VilledeMontreal","download_url":"https://codeload.github.com/VilledeMontreal/authentication-nodejs-lib/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248198892,"owners_count":21063628,"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":["auth","axios","clientcredentials","hacktoberfest","http-client","nodejs","oauth2","oidc","request","superagent"],"created_at":"2024-11-14T04:19:34.509Z","updated_at":"2025-04-10T10:14:13.723Z","avatar_url":"https://github.com/VilledeMontreal.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=ncloc)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=coverage)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=sqale_rating)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=reliability_rating)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=security_rating)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=villedemontreal_authentication-nodejs-lib\u0026metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=villedemontreal_authentication-nodejs-lib)\n\n# authentication-nodejs-lib\n\nThis library handles transparent authentication of backend to backend API calls, using the OpenID Connect protocol.\n\nIt has been designed to cooperate with existing popular http client libraries using their own plugin system,\nin order to satisfy developers and stay out of their way.\n\nThe use of plugins has made the token injection completely transparent, simplifying development\nand reducing the risk of mistakes.\n\n## Why another oauth library?\n\n- dedicated to service to service communication, with service accounts or client credentials.\n  - note that there are many very good libraries for the frontend or for servers protected by OIDC,\n    but not many to properly implement service to service communication.\n- no external libraries\n  - some libraries rely on a specific http client, which is not the one you chose and would\n    unnecessarily increase the number of dependencies in your project.\n- use modern javascript and typescript\n- easy integration with any modern http client lib\n- auto-refresh of tokens\n- optional out of band token refresh (scheduled)\n- proper cache invalidation of bad tokens (and auto retry)\n- proper concurrency handling (renew token once when concurrent requests require it)\n- request correlation\n- easy, simple and clean API\n\n## Points of interest\n\n- 100% code coverage\n- 100% Sonarqube compliant\n- abstraction for any http client lib\n- immutable objects\n- small, composable objects\n- no globals, no singleton\n- fully async\n- factory/builder pattern for easy testing and extensibility\n- concurrency handling to avoid refreshing the same token twice\n  - see SynchronizedAsyncValue\n- auto refresh for expired and invalid access tokens\n- scheduled refresh to avoid refreshing a token while serving a request\n- easy configuration\n- native integration with popular http request libraries (superagent, axios, got...)\n\n## Supported http clients\n\n- [Superagent](https://visionmedia.github.io/superagent/)\n- [Axios](https://github.com/axios/axios)\n- [Request](https://github.com/request/request/) (Note that this module has been deprecated but is still used by some projects such as https://openapi-generator.tech/docs/generators/typescript-node)\n- [Got](https://visionmedia.github.io/got/) (planned)\n\n## Tested OIDC servers\n\n- [oidc-provider](https://www.npmjs.com/package/oidc-provider)\n- [Gluu](https://www.gluu.org/)\n\n## Additional plugins\n\n### Request logger\n\nThis plugin will log information before and after the execution of a request, as well as its elapsed time.\n\n- [Superagent plugin](packages/oidc-plugin-superagent/src/requestLogger.ts)\n- [Axios plugin](packages/oidc-plugin-axios/src/requestLogger.ts)\n- [Request plugin](packages/oidc-plugin-request/src/requestLogger.ts)\n\n### Request correlator\n\nThis plugin will inject the x-correlation-id header in the request.\nNote that a correlation ID can also be injected in the requests handled by a IHttpClient\nwhen the \"correlationIdProvider\" property of the IHttpDefaults is defined.\n\n- [Superagent plugin](packages/oidc-plugin-superagent/src/requestCorrelator.ts)\n- [Axios plugin](packages/oidc-plugin-axios/src/requestCorrelator.ts)\n- [Request plugin](packages/oidc-plugin-request/src/requestCorrelator.ts)\n\n### Request retryer\n\nThis plugin will retry a request if it meets some criteria.\n\n- Superagent: this is a builtin feature of the library\n- [Axios plugin](packages/oidc-plugin-axios/src/retryRequest.ts)\n\n## Usage\n\n### Superagent\n\nHere's the simplest example, using the [Superagent](https://visionmedia.github.io/superagent/) http client:\n\n```\nnpm install superagent @villedemontreal/auth-oidc-plugin-superagent\nnpm install @types/superagent --save-dev\n```\n\n```typescript\nimport * as superagent from 'superagent';\nimport {\n  authenticator,\n  createSession,\n} from '@villedemontreal/auth-oidc-plugin-superagent';\n// configure\nconst session = createSession({\n  authMethod: 'client_secret_basic',\n  client: {\n    id: 'client',\n    secret: 'clientSecret',\n  },\n  issuer: 'http://localhost:5005',\n  scopes: ['openid', 'profile'],\n});\n// custom auth for each http call:\nconst res = await superagent\n  .get('http://localhost:4004/secured/profile')\n  .use(authenticator(session));\nconsole.log(res.status, res.body);\n\n// or configure auth once for all http calls:\nconst myAgent = superagent.agent().use(authenticator(session));\n// then each call will be automatically authenticated\nconst res2 = await myAgent.get('http://localhost:4004/secured/profile');\nconsole.log(res2.status, res.body);\n```\n\n### Axios\n\nHere's the simplest example, using the [Axios](https://github.com/axios/axios) http client:\n\n```\nnpm install axios @villedemontreal/auth-oidc-plugin-axios\nnpm install @types/axios --save-dev\n```\n\n```typescript\nimport axios, { AxiosRequestConfig } from 'axios';\nimport {\n  authenticator,\n  createSession,\n} from '@villedemontreal/auth-oidc-plugin-axios';\n// configure\nconst session = createSession({\n  authMethod: 'client_secret_basic',\n  client: {\n    id: 'client',\n    secret: 'clientSecret',\n  },\n  issuer: 'http://localhost:5005',\n  scopes: ['openid', 'profile'],\n});\n// custom auth for each http call:\nconst config: AxiosRequestConfig = {};\nauthenticator(session).bind(config);\nconst res = await axios.get('http://localhost:4004/secured/profile', config);\nconsole.log(res.status, res.data);\n\n// or configure auth once for all http calls:\nconst myAgent = axios.create();\nauthenticator(session).bind(myAgent);\n// then each call will be automatically authenticated\nconst res2 = await myAgent.get('http://localhost:4004/secured/profile');\nconsole.log(res2.status, res.data);\n```\n\n### Request\n\nHere's the simplest example, using the [Request](https://github.com/request/request/) http client:\n\n```\nnpm install request @villedemontreal/auth-oidc-plugin-request\nnpm install @types/request --save-dev\n```\n\n```typescript\nimport * as request from 'request';\nimport {\n  authenticator,\n  createSession,\n} from '@villedemontreal/auth-oidc-plugin-request';\n// configure\nconst session = createSession({\n  authMethod: 'client_secret_basic',\n  client: {\n    id: 'client',\n    secret: 'clientSecret',\n  },\n  issuer: 'http://localhost:5005',\n  scopes: ['openid', 'profile'],\n});\n// custom auth for each http call:\nconst config: request.CoreOptions = {\n  baseUrl: 'http://localhost:4004',\n};\nauthenticator(session).bind(config);\nrequest.get('/secured/profile', config, (err, res, body) =\u003e {\n  if (err) {\n    console.error(err);\n  } else {\n    console.log(res.statusCode, body);\n  }\n});\n```\n\nNote that the plugins will also work with 'request' promises such as 'request-promise-native' or similar.\n\nNote that this plugin won't implement all features (such as retry or IHttpClient) since the 'request' module has been deprecated. We implemented the bare minimum to help integrate our lib with the https://openapi-generator.tech/docs/generators/typescript-node generator.\n\nThere are a couple of helper functions that make it easy to add OIDC authentication into the generated API classes:\n\n```typescript\nimport {\n  ILogger,\n  IHttpRequestCorrelator,\n} from '@villedemontreal/auth-core';\nimport {\n  IOidcSession,\n  authInterceptor,\n  requestCorrelationInterceptor,\n  requestLoggingInterceptor\n} from '@villedemontreal/auth-oidc-plugin-request';\nimport { OrderApi } from 'OrderApi';\n\nexport function createOrderApi(\n  baseUrl: string,\n  session: IOidcSession,\n  logger: ILogger,\n  correlator: IHttpRequestCorrelator,\n) {\n  const orderApi = new OrderApi(baseUrl);\n  orderApi.addInterceptor(authInterceptor(session));\n  orderApi.addInterceptor(requestLoggingInterceptor(logger));\n  orderApi.addInterceptor(requestCorrelationInterceptor(correlationIdService));\n  return orderApi;\n}\n\nconst orderApi = createOrderApi(...);\nconst res = await orderApi.getOrderById('abc123');\n\n```\n\n## Documentation\n\nFor more information about the configuration options, the flows and the object model, go to the [Documentation](doc) folder.\n\n## Examples\n\nFor a real example, go to the [Examples](examples) folder.\n\n## Developing\n\nThis project is a **monorepo**, that relies on [Lerna](https://lerna.js.org/) to simplify common tasks and take care of interdependencies.\n\n### Unit testing\n\nThe project uses [Jest](https://jestjs.io/) for handling unit tests.\n\nRunning tests:\n\n- From the command-line: `npm t`\n- From VSCode: continuous testing with the [Jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest)\n- From the browser: using the [Majestic test runner](https://github.com/Raathigesh/majestic/)\n\nViewing code coverage:\n\n```\nnpm t\nnpm run show-coverage\n```\n\nDebugging:\n\n- make sure that the coverage feature is disabled while debugging otherwise you won't be able to hit your breakpoints.\n- the project already contains the .vscode folder that exposes 2 debug tasks:\n  - Jest current file\n  - Jest all\n\n### Code quality\n\nFinally, the project is configured to enforce code quality using:\n\n- https://eslint.org/\n- https://prettier.io/\n- https://commitlint.js.org/\n\nAll those quality gates are enforced through the use of Git commit hooks (provided by https://github.com/typicode/husky)\n\nNote that you should install VSCode plugins to enforce those rules when saving files.\n(The project already has the .vscode/settings.json file configured)\n\n### Installation\n\n`npm install`\n\nNote that it will automatically install the modules of each project managed by this mono-repo, then it will compile all projects.\n\n### Build\n\n```shell\nnpm run compile\n```\n\n### Testing\n\nRun unit tests:\n\n`npm run test`\n\nRun linter for Typescript and formatting (Prettier):\n\n`npm run lint`\n\nor\n\n`npm run lint-fix`\n\n## Releasing\n\n### Develop branch\n\nPublish the package as a beta release.\n\nNote that it will patch the current version (but it won't alter the committed package.json file),\ninject a beta tag and a Git sha.\n\nEx: @villedemontreal/auth-core@0.0.6-beta.1+55b3646\n\n```shell\ngit checkout develop\nnpm run publish:dev\n```\n\n### Master branch\n\n```shell\ngit checkout develop\ngit pull\n```\n\nGenerate a new version in package.json, commit it and tag it (should be executed manually):\n\nFirst, edit the root package.json and bump its version.\n\nThen run the following task that will execute a javascript script which copy the root version\ninto each package and it will also adjust the dependencies.\n\n```shell\nnpm run bump\n```\n\nMerge develop into master:\n\n```shell\ngit checkout master\ngit pull\ngit merge develop --ff-only\n```\n\nTag the release:\n```shell\ngit tag v1.x.x\n```\n\n\nPush to Github:\n\n```shell\ngit push\ngit push --tags\n```\n\nNote that any push to the master branch will trigger a Github action that will build, test,\nrun Sonarqube but it won't publish the lib to NPM.\n\nTo publish the lib to npm automatically, you will have to **create a release in Github** using the last tag you just pushed.\nThis will trigger a build that will invoke the `publish:master` task.\n\nHowever, if you need to publish manually, you can execute the following command, providing you\ndid a `npm login` first:\n\n`npm run publish:master`\n\n## License\n\nThe source code of this project is distributed under the [MIT License](LICENSE).\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Code of Conduct\n\nParticipation in this poject is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## TODOs\n\n- add more logs\n- trigger more events\n- implement UMA2\n- implement SCIM\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvilledemontreal%2Fauthentication-nodejs-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvilledemontreal%2Fauthentication-nodejs-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvilledemontreal%2Fauthentication-nodejs-lib/lists"}