{"id":19737974,"url":"https://github.com/devsu/condor-auth","last_synced_at":"2026-05-15T04:02:36.431Z","repository":{"id":57205259,"uuid":"88671488","full_name":"devsu/condor-auth","owner":"devsu","description":"An authorization middleware for Condor. Condor is a GRPC Framework for node.js.","archived":false,"fork":false,"pushed_at":"2017-04-27T23:31:37.000Z","size":36,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-11-04T00:19:16.743Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/devsu.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":"2017-04-18T21:18:32.000Z","updated_at":"2018-09-28T13:59:36.000Z","dependencies_parsed_at":"2022-09-18T01:32:29.409Z","dependency_job_id":null,"html_url":"https://github.com/devsu/condor-auth","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/devsu/condor-auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devsu%2Fcondor-auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devsu%2Fcondor-auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devsu%2Fcondor-auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devsu%2Fcondor-auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devsu","download_url":"https://codeload.github.com/devsu/condor-auth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devsu%2Fcondor-auth/sbom","scorecard":{"id":338436,"data":{"date":"2025-08-11","repo":{"name":"github.com/devsu/condor-auth","commit":"e7360ae4a5f1b8d1a1ecd4f80658580bcfaea5a2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/10 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-18T05:15:11.045Z","repository_id":57205259,"created_at":"2025-08-18T05:15:11.045Z","updated_at":"2025-08-18T05:15:11.045Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33053144,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-15T02:00:06.351Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-12T01:12:57.131Z","updated_at":"2026-05-15T04:02:36.403Z","avatar_url":"https://github.com/devsu.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# condor-auth\n\nAn authorization Middleware for [Condor](http://condorjs.com). **Condor** is a [GRPC Framework for node](https://github.com/devsu/condor-framework).\n\n[![Build Status](https://travis-ci.org/devsu/condor-auth.svg?branch=master)](https://travis-ci.org/devsu/condor-auth)\n[![Coverage Status](https://coveralls.io/repos/github/devsu/condor-auth/badge.svg?branch=master)](https://coveralls.io/github/devsu/condor-auth?branch=master)\n\nThis module control access to **GRPC methods**, based on the **access rules** defined.\n\nIt has been thought to work with [JWTs](https://jwt.io/), but you can plug in any other [strategy](#strategies).\n\n## Installation\n\n```bash\nnpm i --save condor-framework condor-auth\n```\n\n## How to use\n\nBy default, this module is designed to work with **JWts** and **role-based** authorization. Anyways, it's flexible enough to allow any other authorization [strategy](#strategies).\n\n### Role-based authorization\n\nTwo steps are needed for role-based authorization to work:\n\n- [1. Map the roles](#1-mapping-roles): Define how to obtain the roles from the token (or from anywhere else).\n- [2. Configure access rules](#2-configuring-access-rules): Define the roles required to access each of the GRPC methods.\n\n### Resource-based authorization\n\nFor resource based authorization, you can skip step one, and just use **custom validators** when defining the [access rules](#2-configuring-access-rules).\n\n### 1. Mapping Roles \n\nBy default, **condor-auth** expects a valid JWT token in the `authorization` metadata. It will verify it, and convert it to an object you can easily use.\n\nThen, you need to define how to map the information in the token to the roles the user has. \n\nLet's say for example, that the user has the `admin` role in `my-grpc-application`, and the `user` roles in `another-app`.\n\nHere's an example on how you would instantiate **condor-auth** and map the permissions. \n\n```js\n// index.js\n\nconst Condor = require('condor-framework');\nconst Auth = require('condor-auth').Auth;\nconst Greeter = require('./greeter');\n\n// Options must contain any information required to verify the token (see documentation below)\nconst options = {\n  'applicationName': 'my-grpc-service',\n  'secretOrPublicKey': 'shhhhh',\n};\n\nconst auth = new Auth((context, token) =\u003e {\n  // if 'authorization' metadata was received, is a valid token and could be verified \n  // using the received options, 'token' will contain a valid token object\n  console.log('token', token);\n  // do your magic here, to calculate the resources and roles the user has access to\n  // You can get the information from the token (or from anywhere).\n  // Then return an object with the information.\n  return {\n    'my-grpc-service': ['admin'],\n    'another-app': ['user', 'another-role'],\n    'realm': ['admin', 'user', 'yet-another-role'],\n  };\n}, options);\n\n// Then just initiate the server, and use the middleware\nconst app = new Condor()\n  .addService('./protos/greeter.proto', 'myapp.Greeter', new Greeter())\n  .use(auth.middleware)\n  .start();\n```\n\nAs you can see, the mapping method must return an object. This object should be a map with the resource names as the keys, and an array of roles as the values.\n\n## 2. Configuring Access Rules\n\nAfter mapping the roles, you will need to define the rules to access each of the methods in your GRPC service.\n\nBy default, when no options are passed, it will try to read the access rules from `access-rules.js`. This file is where you configure all the access rules for your application.\n\nThe rules file should export an object, with the full names of the services as keys, and an optional `default` key which will be used for every method that is not defined in the file.\n\n### Rules Example\n\nThis example will show you the available options:\n\n```js\n// access-rules.js\n\nmodule.exports = {\n  'default': '$authenticated',\n  'myapp.Greeter': {\n  \t'sayHello': 'special',\n  \t'sayHelloOther': 'other-app:special',\n  \t'sayHelloRealm': 'realm:admin',\n  \t'sayHelloCustom': customValidation,\n  \t'sayHelloPublic': '$anonymous',\n  \t'sayHelloMultiple': ['special', 'realm:admin', customValidation],\n  },\n};\n\nfunction customValidation (context, token) =\u003e {\n\tif (token.hasRole('myRole') \u0026\u0026 context.metadata.get('someKey')[0] === 'someValue') {\n\t\treturn true; // allow to continue\n\t}\n\treturn false; // deny access\n}\n```\n\nUsing these rules, we're telling the application:\n\n- By default, for every method not defined in the file, the user must be authenticated (without taking into account any roles).\n- `sayHello` requires the user to have the `special` permission/role in this application. (`applicationName` option must be set, to determine the name of this application)\n- `sayHelloOther` requires the user to have the `special` permission/role in the `other-app` resource.\n- `sayHelloRealm` requires the user to have the `admin` permission/role in the `realm` resource.\n- `sayHelloCustom` access will be calculated by the `customValidation` method.\n- `sayHelloPublic` will be public (`$anonymous`)\n- `sayHelloMultiple` shows how you can pass not only one but an array of options to authorize the call. In this example, to authorize the method we are requiring any of these 3 conditions:\n\n  - The user to have the `special` permission/role in this application\n  - The user to have the `admin` permission/role in the `realm` resource\n  - The `customValidation` method to return true\n\n### Rules Options\n\n#### $anonynous and $authenticated\n\nYou can use `$authenticated` to enforce a user to be authenticated before accessing the method (without verifying any roles). A user is considered authenticated when the token received in the metadata is valid.\n\nOn the other hand, you can use `$anonymous` to make a resource public.\n\n#### Role and Resource:Role\n\nIf it's a role in the current application, you can just use the permission/role name e.g. `special`. For this to work, you must pass the `applicationName` option when creating the `Auth` instance.\n\nIf it's a permission or role of another application/resource, use the resource name and the role/permission name. e.g. `another-app:special`.\n\n#### Custom Validators\n\nIf you need some specific logic to authorize/deny access, just pass the function that must perform the validation (make sure to pass the actual function, not only the function name).\n\nThe validation function will be called with two parameters: \n\n- `context`: The context being processed.\n- `token`: The decoded token if any, null otherwise.\n\nThe validation function must return a truthy value to allow access. Any falsy value will deny access.\n\n#### Multiple options for a method\n\nYou can pass not only one option, but an array of options to authorize the call. If any of them pass, the call will be authorized.\n\n#### How to require two roles? (use AND instead of OR)\n\nThe module is designed for the most common scenario, but we're sure there will be cases where your requirements will be different, in that case you can use custom validation functions that do exactly what you want. You can have for example something like this:\n \n ```js\n module.exports = {\n   'default': '$authenticated',\n   'myapp.Greeter': {\n   \t'sayHelloCustom': tokenHasAllRoles('special', 'admin'),\n   },\n };\n \nfunction tokenHasAllRoles() {\n  const roles = arguments;\n  return (context, token) =\u003e {\n    // Verify that the token has all the roles\n    return roles.every((role) =\u003e {\n      return token.payload.roles.contains(role);\n    });\n  };\n}\n ```\n\n## Options\n\nAll values are optional. Their default values are:\n\n| Option             | Description                                                                                            | Default         |\n|--------------------|--------------------------------------------------------------------------------------------------------|-----------------|\n| applicationName    | The name of the application. To allow rules like 'my-role', instead of 'my-app:my-role')               |                 |\n| rulesFile          | The path to the rules file                                                                             | access-rules.js |\n| rules              | The access rules to use (can be used instead of rulesFile)                                             |                 |\n| secretOrPublicKey  | The key that should be used to verify a token                                                          |                 |\n| strategy           | The strategy to use (if you don't want to use the default strategy)                                    |                 |\n\nAlso, it will accept any options of the [verify](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback) method of the [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) module. Such options will be used to verify the token.\n\n## Strategies\n\nStrategies allow you to customize:\n\n- How the tokens are verified and decoded\n- How the tokens are mapped to roles\n\nKnown strategies are:\n\n- **Default strategy**: Bundled. It decodes and verifies JWTs using [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken) module. It doesn't provide a mapping method.\n- **[condor-auth-keycloak](https://github.com/devsu/condor-auth-keycloak)**. It verifies the token against keycloak, and map realm roles and resources roles automatically.\n\n### How to create your own strategy\n\nYou will to define the following methods:\n\n- **mapRoles(context, token)**: (Optional): This method receives the context, and token, and should return an object with the resource names as keys and an array of roles the user has, as values.\n- **decodeAndVerifyToken(context, options)**: (Optional): This method receives the context, and all the options passed in the `Auth` constructor. It should return the decoded token if valid, or null/undefined otherwise. Any thruthy value will be consider as a valid token, and the user will be considered to be authenticated. You can take a look at the **DefaultStrategy** to see an example of the implementation. \n\n## How to call from a client\n\nThe caller just need to include the `authorization` metadata, with a valid JWT.\n\n```js\nconst grpc = require('grpc');\nconst jwt = require('jsonwebtoken');\n\nconst proto = grpc.load('./protos/greeter.proto');\nconst client = proto.myapp.Greeter('127.0.0.1:3000', grpc.credentials.createInsecure());\n\nconst myJWT = jwt.sign({ roles: 'myRole' }, 'shhhhh');\n\nconst data = {'name': 'Peter'};\nconst metadata = new grpc.Metadata();\nmetadata.set('authorization', myJWT);\n\nclient.sayHello(data, (err, result) =\u003e {\n  console.log('err', err);\n  console.log('result', result);\n});\n```\n\n## License and Credits\n\nMIT License. Copyright 2017 \n\nBuilt by the [GRPC experts](https://devsu.com) at Devsu.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevsu%2Fcondor-auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevsu%2Fcondor-auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevsu%2Fcondor-auth/lists"}