{"id":13583670,"url":"https://github.com/iad-os/nightswatch","last_synced_at":"2025-04-12T10:37:04.996Z","repository":{"id":42927538,"uuid":"241946293","full_name":"iad-os/nightswatch","owner":"iad-os","description":"⚔️Night's Watch, the OIDC Relying Party that guards the realms","archived":false,"fork":false,"pushed_at":"2022-12-12T02:22:16.000Z","size":314,"stargazers_count":30,"open_issues_count":12,"forks_count":5,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-26T05:33:07.888Z","etag":null,"topics":["oidc","relying-party"],"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/iad-os.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":"2020-02-20T17:26:09.000Z","updated_at":"2023-10-24T08:53:56.000Z","dependencies_parsed_at":"2023-01-27T11:15:22.919Z","dependency_job_id":null,"html_url":"https://github.com/iad-os/nightswatch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iad-os%2Fnightswatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iad-os%2Fnightswatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iad-os%2Fnightswatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iad-os%2Fnightswatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iad-os","download_url":"https://codeload.github.com/iad-os/nightswatch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248554755,"owners_count":21123742,"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":["oidc","relying-party"],"created_at":"2024-08-01T15:03:41.156Z","updated_at":"2025-04-12T10:37:04.969Z","avatar_url":"https://github.com/iad-os.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\t\u003cimg  src=\"./logo.png\" alt=\"Night's Watch Logo\"\u003e\n\t\u003chr\u003e\n\t\u003ch2\u003e\n\t\tThe OIDC Relying Party that guards the realms\n\t\u003c/h2\u003e\n\t\u003chr\u003e\n\u003c/div\u003e\n\n- [Getting Started](#getting-started)\n- [Configuration](#configuration)\n- [Run Night's Watch](#run-nights-watch)\n  - [Run with node](#run-with-node)\n  - [🐳 Run with Docker](#%f0%9f%90%b3-run-with-docker)\n  - [🐳 Run with Docker Compose](#%f0%9f%90%b3-run-with-docker-compose)\n- [Configure Authorization Headers](#configure-authorization-headers)\n  - [Example of: Adding a custom Header](#example-of-adding-a-custom-header)\n  - [The Token Set claims](#the-token-set-claims)\n  - [The UserInfo claims](#the-userinfo-claims)\n  - [The IdToken claims](#the-idtoken-claims)\n\n## Getting Started\n\n## Configuration\n\nThe following is the default configuration; you can use it to create your own `Night's Watch` configuration.\n\n```yaml\noidc:\n  issuerUri: https://issuer.castle_black.com\n  client_id: the_wall\n  client_secret: the_key_of_the_wall\n  redirect_uri: https://north.7kingdoms.com/oidc/callback\n  scopes: openid profile email offline_access\n\n# https://github.com/expressjs/cookie-session\ncookie:\n  name: nightswatch\n  keys:\n    - you_know_nothing_jon_snow\n  maxAge: 24h\ntargets:\n  path: /**\n  upstream: http://httpbin.org\n  routes: []\n  #  - path: /_dev\n  #    upstream: http://httpbin.org\n  rewrite: []\n  #  - match: ^/_dev\n  #    rewrite: '/headers'\n\nstorage:\n  kind: InMemory\n  specs:\n    stdTTL: 24h\nserver:\n  # max_body_limit: 100k\n  http:\n    enable: true\n    port: 3000\n  # to be implemented\n  https:\n    enable: false\n    port: 3001\n  max_header_size: 8192\n  proxy:\n    # http://expressjs.com/en/guide/behind-proxies.html\n    # loopback - 127.0.0.1/8, ::1/128\n    # linklocal - 169.254.0.0/16, fe80::/10\n    # uniquelocal - 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7\n    - loopback\n    - linklocal\n    - uniquelocal\n    # add your own reverse proxy ip or a network\n    # - x.x.x.x/x\n  healthchecks:\n    readiness: /healthcheck/ready\n    liveness: /healthcheck\n    timeout: 2s\nrelying_party:\n  on_success_redirect: /\n  on_fail_redirect: /\n  oidc_base_path: /oidc\n  oidc_paths:\n    login: /login\n    callback: /callback\n  rules:\n    - route: /**\n      methods:\n        - all\n  logLevel: error\n  headers:\n    prefix: X-AUTH\n    proxy:\n      access-token: tokenset.access_token\n      id-token: tokenset.id_token\n      expires-at: tokenset.expires_at\n      expires-in: tokenset.expires_in\n      sub: idtoken.sub\n      name: idtoken.name\n      email: idtoken.email\n      family-name: idtoken.family_name\n      given-name: idtoken.given_name\n```\n\nAll of the options can be provided as ENVIRONMENT variables by applying this rule:\n\n`replace('.', '__').toUpperCase()`\n\nIn order to set the HTTP headers prefixes that we're going to send to the upstream, we can use the config.yaml file:\n\n```yaml\nrelying_party:\n  headers:\n    prefix: X-AUTH\n```\n\nA variable named `RELYING_PARTY__HEADERS__PREFIX` could also be set, instead.\n\n\nThe mandatory configuration part is the following:\n\nWith a _config.minimal.yaml_\n\n```yaml\noidc:\n  issuerUri: https://issuer.castle_black.com\n  client_id: the_wall\n  client_secret: J0n_Sn0w_is_Aeg0n_T@rg@ryen\n  redirect_uri: https://north.7kingdoms.com/oidc/callback\ncookie:\n  keys:\n    - you_know_nothing_jon_snow\ntargets:\n  upstream: http://httpbin.org\n```\n\nand here is its alternative, through a _.env file or environment variables:_ \n\n```shell\nOIDC__ISSUERURI=https://issuer.castle_black.com\nOIDC__CLIENT_ID=the_wall\nOIDC__CLIENT_SECRET=J0n_Sn0w_is_Aeg0n_T@rg@ryen\nOIDC__REDIRECT_URI=https://north.7kingdoms.com/oidc/callback\nCOOKIE__KEYS_0=you_know_nothing_jon_snow\nTARGET__UPSTREAM=http://httpbin.org\n```\n\n## Run Night's Watch\n\nYou can run Night's Watch in different scenarios:\n\n[Run with node](#run-with-node)\n[🐳 Run with Docker](#%f0%9f%90%b3-run-with-docker)\n[🐳 Run with Docker Compose](#%f0%9f%90%b3-run-with-docker-compose)\n⎈ Run in Kubernetes: (soon)\n\n### Run with node\n\nNight's Watch is developed using NodeJS 12; check your installed version with `node --version` or install it from the official website.\n\nOnce you have checked the node version, you can go ahead and clone the repository:\n\n```shell\n$ git clone https://github.com/iad-os/nightswatch.git\n```\n\nnext, run `npm install` to download dependencies and, finally, finally `npm start` or `npm run start-pretty`, for a prettier console logging.\n\nIn order to pass environment variables, a `.env` file can be created in the checkout folder; otherwise, they can be passed with this npm start command:\n`CONFIG_FILE=./recipes/simple/config.simple.yaml npm run start`.\n\nIt is also possible to use a .yaml configuration:\n\n```shell\n$ cp /src/config.default.yaml ./config.yaml\n```\n\nUse your own editor to configure Night's Watch the way you need it, then run it with `npm start` or `npm run start-pretty`.\n\nIf not overridden, the CONFIG_FILE is set to `./config.yaml` by default and Night's Watch will try to read your configuration from `config.yaml` in the current folder.\n\n### 🐳 Run with Docker\n\nThe official Night's Watch docker image is available at Docker Hub [iad2os/nightswatch](https://) and can be executed with the following command:\n\n```shell\n$ docker run \\\n-e OIDC__ISSUERURI=https://issuer.castle_black.com \\\n-e OIDC__CLIENT_ID=the_wall \\\n-e OIDC__CLIENT_SECRET=J0n_Sn0w_is_Aeg0n_T@rg@ryen \\\n-e OIDC__REDIRECT_URI=https://north.7kingdoms.com/oidc/callback \\\n-e COOKIE__KEYS_0=you_know_nothing_jon_snow \\\n-e TARGET__UPSTREAM=http://httpbin.org \\\n-p 3000:3000 \\\niad2os/nightswatch\n\n```\n\na volume mount or a .env file can also be used modifying the `docker run` as follows:\n\n(with volumes)\n\n```shell\n$ docker run \\\n-v /path/to/config.yaml:/app/config.yaml\n-p 3000:3000 \\\niad2os/nightswatch\n\n```\n\n(with .env)\n\n```shell\n$ docker run \\\n-env /path/to/.env\n-p 3000:3000 \\\niad2os/nightswatch\n\n```\n\n### 🐳 Run with Docker Compose\n\nLet's start creating a docker compose file, in this example scenario we will make http://httpbin.org safe with the aid of the Night's Watch. This will come in handy later, while verifying that everything works as expected.\n\n```yaml\nversion: '3.4'\nservices:\n  nightswatch:\n    image: iad2os/nightswatch\n    volumes:\n      - ./config-simple.yaml:/app/config.yaml\n    environment:\n      DEBUG: nightswatch:*\n      CONFIG_FILE: ./config.yaml\n    ports:\n      - 3000:3000\n    healthcheck:\n      test:\n        [\n          'CMD',\n          'wget',\n          '--quiet',\n          '--spider',\n          'http://localhost:3000/healthcheck',\n        ]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 5s\n```\n\n## Configure Authorization Headers\n\nWith Night's Watch you can easily customize the headers passed to the Resource Server (in other words, your application).\n\nFor each request, Night's Watch will add some headers that a resource server may consume to bind the identity and other details needed to handle such request.\n\nHere is the default headers and its configuration:\n\n```yaml\nrelying_party\n  headers:\n    prefix: X-AUTH\n    proxy:\n      access-token: tokenset.access_token\n      id-token: tokenset.id_token\n      expires-at: tokenset.expires_at\n      expires-in: tokenset.expires_in\n      sub: idtoken.sub\n      name: idtoken.name\n      email: idtoken.email\n      family-name: idtoken.family_name\n      given-name: idtoken.given_name\n```\n\nyou can configure your own headers and decide what to send to the upstream, north of the Wall!\n\nEvery request comes with 3 objects:\n\n- [The Token Set claims](#the-token-set-claims)\n- [The UserInfo claims](#the-userinfo-claims)\n- [The IdToken claims](#the-idtoken-claims)\n\nhere is a JSON example:\n\n```json\n{\n  \"tokenset\": {\n    \"access_token\": \"theAccessToken\",\n    \"expires_at\": 1583084430,\n    \"refresh_expires_in\": 0,\n    \"refresh_token\": \"theRefreshToken\",\n    \"token_type\": \"bearer\",\n    \"id_token\": \"oidcIdToken\",\n    \"not-before-policy\": 0,\n    \"session_state\": \"aRandomId\",\n    \"scope\": \"openid offline_access email profile\"\n  },\n  \"userinfo\": {\n    \"sub\": \"459697e5-6c58-45d8-88f2-2a4ea5b3157a\",\n    \"email_verified\": true,\n    \"name\": \"Jeor Mormont\",\n    \"preferred_username\": \"The Old Bear\",\n    \"given_name\": \"Jeor\",\n    \"family_name\": \"Mormont\",\n    \"email\": \"theoldbear@castle_black.com\"\n  },\n  \"idtoken\": {\n    \"jti\": \"88ae774f-4121-4a9a-8584-2a8d13831130\",\n    \"exp\": 1583084430,\n    \"nbf\": 0,\n    \"iat\": 1583084370,\n    \"iss\": \"https://issuer.castle_black.com\",\n    \"aud\": \"1min-access-token\",\n    \"sub\": \"459697e5-6c58-45d8-88f2-2a4ea5b3157a\",\n    \"typ\": \"ID\",\n    \"azp\": \"1min-access-token\",\n    \"auth_time\": 1583084369,\n    \"session_state\": \"99bd9ca8-cd06-469c-90ea-4fddcc3bcdee\",\n    \"acr\": \"1\",\n    \"email_verified\": true,\n    \"name\": \"Jeor Mormont\",\n    \"preferred_username\": \"The Old Bear\",\n    \"given_name\": \"Jeor\",\n    \"family_name\": \"Mormont\",\n    \"email\": \"theoldbear@castle_black.com\"\n  }\n}\n```\n\n### Adding a custom Header (sample)\n\nFor instance, you could add a header named `X-AUTH-ROLES`, representing user roles.\nusing an environment variable:\n\n```shell\nRELYING_PARTY__HEADERS_PROXY_ROLES=idtoken.roles\n```\n\nusing config.yaml\n\n```yaml\nrelying_party\n  headers:\n    prefix: X-AUTH\n    proxy:\n      roles: idtoken.roles\n```\n\n⚠️ IdToken may differ between issuer; which claim to include can also be configured. Please refer to your IDP documentation.\n\n### The Token Set claims\n\nAn object named tokenset will be available with the following properties:\n\n```\naccess_token: \u003cstring\u003e\ntoken_type: \u003cstring\u003e\nid_token: \u003cstring\u003e\nrefresh_token: \u003cstring\u003e\nexpires_in: \u003cnumber\u003e\nexpires_at: \u003cnumber\u003e Access token expiration timestamp, formed by the number of seconds since the epoch (January 1, 1970 00:00:00 UTC).\nsession_state: \u003cstring\u003e\nother properties may be present and they'll be passthrough available on the TokenSet instance\n```\n\nThis is an example of TokenSet object:\n\n```yaml\ntokenset\n access_token: theAccessToken\n expires_at: 1583084430\n refresh_expires_in: 0\n refresh_token: theRefreshToken\n token_type: bearer\n id_token: oidcIdToken\n not fore-policy: 0\n session_state: aRandomId\n scope: openid offline_access email profile\n```\n\nfor more details, check the official TokenSet documentation at [panva/node-openid-client](https://github.com/panva/node-openid-client/blob/master/docs/README.md#class-tokenset).\n\n### The UserInfo claims\n\nThe UserInfo object contains the claims defined by the OIDC standards, and this can change between OIDC providers. If you also control the OIDC provider, consult the documentation to configure what claims are included in the UserInfo endpoint.\nMore info about UserInfo and standard claims can be found at [OIDC Specs - User Info](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo)\n[OIDC Specs - Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)\n\nThis is an UserInfo object example:\n\n```yaml\nuserinfo:\n  sub: 459697e5-6c58-45d8-88f2-2a4ea5b3157a\n  email_verified\": true\n  name: Jeor Mormont\n  preferred_username: The Old Bear\n  given_name: Jeor\n  family_name: Mormont\n  email: theoldbear@castle_black.com\n```\n\n### The IdToken claims\n\nEven though you have a serialized and JWT-signed id_token located at the `tokenset.id_token` level, the root-level `idtoken` object contains the same content but, indeed, as an object.\nWith this, it will be more convenient to handle claims in the headers..\n\nHere is an example of `idtoken` object:\n\n```yaml\nidtoken:\n  jti: 88ae774f-4121-4a9a-8584-2a8d13831130\n  exp: 1583084430\n  nbf: 0\n  iat: 1583084370\n  iss: https://issuer.castle_black.com\n  sub: 459697e5-6c58-45d8-88f2-2a4ea5b3157a\n  typ: ID\n  azp: 1min-access-token\n  auth_time: 1583084369\n  session_state: 99bd9ca8-cd06-469c-90ea-4fddcc3bcdee\n  acr: 1\n  email_verified: true\n  name: Jeor Mormont\n  preferred_username: The Old Bear\n  given_name: Jeor\n  family_name: Mormont\n  email: theoldbear@castle_black.com\n```\n\nCheck out the official OIDC docs: [OIDC Specs](https://openid.net/specs/openid-connect-core-1_0.html#IDToken)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiad-os%2Fnightswatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiad-os%2Fnightswatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiad-os%2Fnightswatch/lists"}