{"id":17858615,"url":"https://github.com/vzakharchenko/keycloak-api-gateway","last_synced_at":"2025-07-27T23:30:49.997Z","repository":{"id":44888637,"uuid":"373882929","full_name":"vzakharchenko/keycloak-api-gateway","owner":"vzakharchenko","description":"Login flow gateway through Keycloak for static Web resources(bundle.js, images, pdf etc...)","archived":false,"fork":false,"pushed_at":"2022-01-24T14:07:51.000Z","size":873,"stargazers_count":10,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-28T05:36:14.582Z","etag":null,"topics":["api-gateway","aws","aws-lambda-edge","express","frontend","keycloak","lamda-edge","middleware","multi-tenant-application"],"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/vzakharchenko.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-06-04T15:21:43.000Z","updated_at":"2024-06-06T17:56:54.000Z","dependencies_parsed_at":"2022-09-10T19:01:18.438Z","dependency_job_id":null,"html_url":"https://github.com/vzakharchenko/keycloak-api-gateway","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vzakharchenko%2Fkeycloak-api-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vzakharchenko%2Fkeycloak-api-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vzakharchenko%2Fkeycloak-api-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vzakharchenko%2Fkeycloak-api-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vzakharchenko","download_url":"https://codeload.github.com/vzakharchenko/keycloak-api-gateway/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227732303,"owners_count":17811362,"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":["api-gateway","aws","aws-lambda-edge","express","frontend","keycloak","lamda-edge","middleware","multi-tenant-application"],"created_at":"2024-10-28T05:22:33.185Z","updated_at":"2024-12-03T03:13:09.060Z","avatar_url":"https://github.com/vzakharchenko.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# keycloak-api-gateway\n\n- [![Node.js 10.x, 12.x, 13.x, 14.x, 15.x CI](https://github.com/vzakharchenko/keycloak-api-gateway/actions/workflows/nodejs.yml/badge.svg)](https://github.com/vzakharchenko/keycloak-api-gateway/actions/workflows/nodejs.yml)\n- [![npm version](https://badge.fury.io/js/keycloak-api-gateway.svg)](https://badge.fury.io/js/keycloak-api-gateway)\n- [![Coverage Status](https://coveralls.io/repos/github/vzakharchenko/keycloak-api-gateway/badge.svg?branch=master)](https://coveralls.io/github/vzakharchenko/keycloak-api-gateway?branch=master)\n- [![Maintainability](https://api.codeclimate.com/v1/badges/7d57b4bb709970045ad3/maintainability)](https://codeclimate.com/github/vzakharchenko/keycloak-api-gateway/maintainability)\n- [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=vzakharchenko_keycloak-api-gateway\u0026metric=security_rating)](https://sonarcloud.io/dashboard?id=vzakharchenko_keycloak-api-gateway)\n- [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=vzakharchenko_keycloak-api-gateway\u0026metric=sqale_index)](https://sonarcloud.io/dashboard?id=vzakharchenko_keycloak-api-gateway)\n- [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=vzakharchenko_keycloak-api-gateway\u0026metric=bugs)](https://sonarcloud.io/dashboard?id=vzakharchenko_keycloak-api-gateway)\n\nLogin flow gateway through [Keycloak](https://www.keycloak.org/) for static Web resources(bundle.js, images, pdf etc...)\n\n## Features\n- lambda@edge or expressjs middleware\n- authorization based on realm/client role and security resources\n- protect frontend static web resources(bundle.js and other files)\n- support Multi-Tenancy\n- change behaviour of static web resource (dynamically replace to another resource)\n- dynamically create web resources.\n- redirect to another services\n- work as Express middleware\n- easily transform to aws lambda@edge\n\n# Examples\n- [Single Tenant ReactJS Application (Authorization based on Client Role)](./examples/reactJSExample)\n- [Multi-tenant  ReactJS Application with Tenant selector (Authorization based on Realm Role)](./examples/multiTenantReactJSExample)\n- [Cross-tenant  ReactJS Application with Tenant selector and approval proccess (Authorization based on security resources)](./examples/crossTenantReactJSExample)\n- [Custom Storage example](./examples/customStorageExample)\n\n# Installation\n\n```\nnpm i keycloak-api-gateway -S\n```\n\n**Import Adapter**\n```js\nimport { KeycloakApiGateWayAdapter } from 'keycloak-api-gateway/dist';\n```\nor\n```js\nconst { KeycloakApiGateWayAdapter } = require('keycloak-api-gateway/dist');\n```\n\n# Configuration for Single-Tenant Application\n![](./imgs/keycloak-api-gateway.png)\n```json\n{\n  \"defaultAdapterOptions\": {\n    \"keycloakJson\": {\n      \"realm\": \"express-example\",\n      \"auth-server-url\": \"http://localhost:8090/auth/\",\n      \"ssl-required\": \"external\",\n      \"resource\": \"express-example\",\n      \"credentials\": {\n        \"secret\": \"express-example\"\n      },\n      \"use-resource-role-mappings\": true,\n      \"confidential-port\": 0\n    }\n  },\n  \"storageType\": \"InMemoryDB\",\n  \"keys\": {\n    \"privateKey\": {\n      \"key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD40tysViQSnd3E\\nIe5+6hDM/7ixHND8UoxYAKWwnA2/PdH2lq/pzjOo1t1Jt6ZbZx2l3cNUDt7FQXHL\\nvZeEn0w75/LVe/gIeoKJIUTWrXyVOrrPn50oWiaKX5pnMCLWUwk1usRwnP7o26SH\\nURTebSfBI7kQfh22aiv68qgGvo4lMWISVrWNCNej4oItLafRzvgBBD7GvJhqvPIW\\nTMFyqDzGRtVk8nYi9x3Wwp72eUW9aY/j/akPTLdU5a+uAjlQYDrPa0wkg+/2KIhx\\nGD/ffyggjvUaopzOEbnNGyBVXiOS3rQwwQnXNq+ip0xVecYVDJBlpOdQAxE77fUl\\nRrw5DzKtAgMBAAECggEASLuyf7nKX5q/2XYltfmLobDadwM6X5dtqMe/pylmp1FV\\nz6PqlgiNdzwfgU3qletFclepoieanMRtlCW+Zaj+6r/5bsgHD8tn3tfXvH0H3sNF\\nGi3JDaOUgnxBsQoUFNw+4/LNOzHZHY4ewONFm2MC7OUZUqXa35iXdIp77UTEXkBG\\nn4QdMraDW1DJUCx8nlUXHPntFN1AJANnx92Nsg6ZbhQrRRH4Lw8ydnUa3bN+Cy12\\n9secVwo2RVS8slJgW21UpkVKEdUxe0VIL2++0trMokGK219AwlQV86hzEDmVUum2\\nRIR3S0eknzvkJKspYc0tVvy/1uWnZggeJ+mNo1w4DQKBgQD/jpEpcdYJ9tHtBI3L\\ne8s2Q4QLqdVPScS5dMDCw0aE6+CQoDSr0l37tHy5hxPJT+WalhyLCvPVtj0H97NP\\nZLAoF/pgARpd3qhPM90R7/h7HgqxW/y+n1Qt/bAG+sR6n8LCcriYU+/PeUp1ugSW\\nAYipqpexeRHhbwAI6pAWBj9ZXwKBgQD5QU5q6gnzdM20WVzp3K4eevpaOt9w/OUW\\neI6o9wgVkvAo0p9irq8OM1SQlL3w3cX/YHktG9iF5oNRW6M2p7aKN1d5ZlUDhr1k\\n/ogbtqg2CTWUikac4cUlZcour589DExlpvVL3zQda5/L7Cr0RrBmKRjMb1fyPXsy\\nWJIllAgTcwKBgQDta7AlBuNJQotpXe+1+f6jHTqR82h/TxN7EKL8zpq3ZsSs2InW\\nj4xNCjNN0dZqEtZHNeqyqqw6AiLVQiTOP8cAmLY9dwjd6LwJSS+7OGxrRU+90q4P\\nEssMJ0HgWh0rpz0zlY01x9VltVOd6AHWsvoaVqizcr1P6OXpYrIWJBu6lQKBgQDS\\n5isP048v67jRzHsNdafuKmgCSKYe2ByOcttipAK3HmkOYYhy2xNLlKsM2o4Ma9nI\\nRzzAqjr+sRiTklH7QNT3BfSBx9BO94bxGVzY9ihF8Gzhjk5JF87T4di8v+SgpvNN\\nX4NV+zoBWrsOtHlzzwwapNNSxzNGyDahVsfx+9sJeQKBgFuvm70VulN5Rd4TMcF2\\nWixQNHEDStWBWPTa15ehDRIvxqfGZCkuY5o9tGY1vHxnpiHhqVheyRtLuHI6j5b3\\nil3T5+cXdt1MnmkXUksqwgwcJdMqI5fmcuO9vdeYuGV4MoXysBdKMhqPybcVIonT\\n5coMCbW92hodfPZ3F93PQpJU\\n-----END PRIVATE KEY-----\\n\"\n    },\n    \"publicKey\": {\n      \"key\": \"-----BEGIN CERTIFICATE-----\\nMIIDjzCCAnegAwIBAgIUNC48rSIoaMJC9YAcJ/MnfQcBmDgwDQYJKoZIhvcNAQEL\\nBQAwVjELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By\\naW5nZmllbGQxDDAKBgNVBAoMA0RpczESMBAGA1UEAwwJZGV2c2VydmVyMCAXDTIx\\nMDYwNzIwMTQzOVoYDzIxMjEwNTE0MjAxNDM5WjBWMQswCQYDVQQGEwJVUzEPMA0G\\nA1UECAwGRGVuaWFsMRQwEgYDVQQHDAtTcHJpbmdmaWVsZDEMMAoGA1UECgwDRGlz\\nMRIwEAYDVQQDDAlkZXZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\\nAoIBAQD40tysViQSnd3EIe5+6hDM/7ixHND8UoxYAKWwnA2/PdH2lq/pzjOo1t1J\\nt6ZbZx2l3cNUDt7FQXHLvZeEn0w75/LVe/gIeoKJIUTWrXyVOrrPn50oWiaKX5pn\\nMCLWUwk1usRwnP7o26SHURTebSfBI7kQfh22aiv68qgGvo4lMWISVrWNCNej4oIt\\nLafRzvgBBD7GvJhqvPIWTMFyqDzGRtVk8nYi9x3Wwp72eUW9aY/j/akPTLdU5a+u\\nAjlQYDrPa0wkg+/2KIhxGD/ffyggjvUaopzOEbnNGyBVXiOS3rQwwQnXNq+ip0xV\\necYVDJBlpOdQAxE77fUlRrw5DzKtAgMBAAGjUzBRMB0GA1UdDgQWBBRJRP2WG0uR\\nvDPnSRmV6Y8Rxu6ErDAfBgNVHSMEGDAWgBRJRP2WG0uRvDPnSRmV6Y8Rxu6ErDAP\\nBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDhKnZDt5VwTroWcTtX\\nLSqIDtLLHiZxk6PIE8X9DG+rU//4Rfd+MFHClcKWiyLgYZPdgPaXSDXPiyfxlb7v\\njOA0F0PXbEpR/RmjM5A+x3gljSufrWgedEC6rFFEg5Ju1IY+/7nJYkvd3ICMiLB3\\ngOczMEp/tI7m89DS+bJAGG8AIYeBjj+3OjuGdEFtXpkt1ri33LYC4wK+rjqkBMyi\\njqwex5bEkloSuyWP/IIDa8OpBWUM17H9ZswG74kQr5/wsvvTxc/JvRmMtNrbUyKa\\n2JKXA1IJgNPP4/v2FxiGTibidZVf0fyXVqarU5Ngj/fVQyn7EBg+VGqPintiL5xU\\ngUsi\\n-----END CERTIFICATE-----\\n\"\n    }\n  }\n}\n\n```\nexample: [Single Tenant ReactJS Application](./examples/reactJSExample)\n# Configuration for Multi-Tenant Application\n![](/imgs/multi-tenant-keycloak-api-gateway.png)\n```js\n{\n  multiTenantJson(tenantName) {\n    return {\n        \"realm\": tenantName,\n        \"auth-server-url\": \"http://localhost:8090/auth/\",\n        \"ssl-required\": \"external\",\n        \"resource\": \"multiTenantreactJsExample\"\n    }\n  },\n  multiTenantAdapterOptions: {\n    \"multiTenantAdapterOptions\": {},\n    keys:{\n      privateKey:{\n        key: \"-----BEGIN PRIVATE KEY-----\\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDe8j3ZTRd2Rpaz\\niLG33ItRWrL/p5wS+IEM3c4WFDzJvLKSTafFS78l3EuJz5bXuOQtKd6TrpXLkCG/\\n1CQqaD7EPiMK11AQ3/mmALO6PSsXtFqTBk50NgUU64XmLt7nLG9FFgfK0Ez0p2HV\\nTTkzbTCczUyktPte596b/7YMCFT7OozNjvCuSpNEFrGvSd3W1TN9nvlSy/YDb5x6\\n+d8AWGGgyv7e/ziOLhvkD9XpsxApXbK6VxS6LHaZs5rYz5oIc10Q3Oizw5lSmW6P\\nj9Izu0NxySQNNIa1RUaZnxUYratO0J8sqn0UwH6S6opUwYWmrRMJ+Ke6tWIzjlEx\\n8hh+V/55AgMBAAECggEBALeY4dobpGCgjOZYgZIaKxjaCmKC0wLEZvIDjv2buNuh\\na6UUEj9lu4ogOozIyT3pYu7WdhdERNOYZFKnDwllQ5s0WINLAQKEkABmv5t1WBFz\\nUsuU+/KzsceilWgT3Tie3RsVo2Ef3N/1H5oauCpjlw7p+l4BNKjZZfctw+twyRsB\\neMKUaRyjelbsfyK8iuT/ghPUHXCaxELcahagGy153q2YQBsBzb7dVz/MMaDtAEvF\\noQDhs3Rnwz8WbY6+GwGGh+yivLiA2dFZGaZNHC3MZZf7uOogb/gmG7EA7hM8/EwW\\nds81xYzuZBIWLaCwsQ8SvlmnSrGX/2X07BHkuZh6M6ECgYEA+C+uu3JHNmmNpzLg\\nW0ZJeNpaIGn788G5O5fSvWTnYrRxk/RLc7Fs7IpXcS7RZ1v6hOJHnvf6ZGMt2JnN\\nGF3HAcefOLev3G2fEF3F/+zPJP+Ul/86Z9UmQZXb5PrFWkInCFeVRHp9AOl9DLBD\\nROkHgRdL5NYJqTxsyT2gQC4wsd0CgYEA5fchkErztHY/NI3LHIlrWutqLl9Fys7y\\nrmYM1b5d3DuUBzlbeOOldtF5ZQmqfPXZSRP5sh9NYpmErwen/DCZlbzo6ErKbDfZ\\nk7ZLs8XXxdGu5LpdJwC6DYdNhMaa+SsopBisWddBFgHfGwEyOi1V0VYnlaprOhSM\\nQcR71fRmC00CgYA2ku2eREvKeD1w1awmBfej/oew9v0zJZcgtordoLGMr9cFzMNG\\npm4oOWdu+PeM/dnBnKxZFXhW2MQ9C9zgjcZz6rxlUWb3VpeSlrwyQZVvMlAveC0U\\npfcqltRqroX1CfThTbkB/Nk9+RnJT30LSx6eUUwb/sDTGPlm6wkw87c7dQKBgQCh\\nzBTDTtjUmXWy5iiHtW/hEk0svz99h8lbRtW09TFYqFpoEsT280QRqyQ8IGbhcKAm\\nOHWwCzIJM3YVJ8/bMd59aeJ8vVJafZkJwnLU01gTCIqCx1SPAoXkytORnaKfuOvp\\nOKraswZKE5sDhv3tzMPae0Fyneq/fIGKLFHsoP3C6QKBgQDnFxoXmn5k3BFgW9aK\\ne/BguKqg7JxUh153b9LcQWKvKs+Tz48t30/aHCH9mRgs1ebL7Z0TVKqSq5Y1G/Aq\\nodiJX67LkQSsPTorFY+yPynHdIEyduGuiTE2dUUgtNwZUPwTxHIah9WmvhGth9kh\\n7oXH27nU0UCpkWtgvHpDHZPevg==\\n-----END PRIVATE KEY-----\\n\"\n      },\n      publicKey:{\n        key: \"-----BEGIN CERTIFICATE-----\\nMIIDrTCCApWgAwIBAgIUOCkhWHsiDBi+aZXdx0/ItJ4dtkcwDQYJKoZIhvcNAQEL\\nBQAwZjELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By\\naW5nZmllbGQxDDAKBgNVBAoMA0RpczEiMCAGA1UEAwwZbXVsdGlUZW5hbnRyZWFj\\ndEpzRXhhbXBsZTAeFw0yMTA2MTYwODI1MTFaFw0yMjA2MTYwODI1MTFaMGYxCzAJ\\nBgNVBAYTAlVTMQ8wDQYDVQQIDAZEZW5pYWwxFDASBgNVBAcMC1NwcmluZ2ZpZWxk\\nMQwwCgYDVQQKDANEaXMxIjAgBgNVBAMMGW11bHRpVGVuYW50cmVhY3RKc0V4YW1w\\nbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDe8j3ZTRd2RpaziLG3\\n3ItRWrL/p5wS+IEM3c4WFDzJvLKSTafFS78l3EuJz5bXuOQtKd6TrpXLkCG/1CQq\\naD7EPiMK11AQ3/mmALO6PSsXtFqTBk50NgUU64XmLt7nLG9FFgfK0Ez0p2HVTTkz\\nbTCczUyktPte596b/7YMCFT7OozNjvCuSpNEFrGvSd3W1TN9nvlSy/YDb5x6+d8A\\nWGGgyv7e/ziOLhvkD9XpsxApXbK6VxS6LHaZs5rYz5oIc10Q3Oizw5lSmW6Pj9Iz\\nu0NxySQNNIa1RUaZnxUYratO0J8sqn0UwH6S6opUwYWmrRMJ+Ke6tWIzjlEx8hh+\\nV/55AgMBAAGjUzBRMB0GA1UdDgQWBBS+MiDLDReuMpw4d2iF1si0IxfHKzAfBgNV\\nHSMEGDAWgBS+MiDLDReuMpw4d2iF1si0IxfHKzAPBgNVHRMBAf8EBTADAQH/MA0G\\nCSqGSIb3DQEBCwUAA4IBAQBaozLIBUH1aMCRL5LtVc9GaJt9NNT4O1dWJFShOfnH\\nFqZ6VHfcBKrEDwLerG2PgGiDZABkCZe31KvQQk3eib3uGZnIWyaCr8uE3b/GOUds\\nKpqTbjrSlYfP0rTi4CqT2PNLDkC78FtL4m7J8OF1nwFDIExaBz+75K0wDnGMOv84\\nPLwjX2TrtQ53IVvkMgxVGC9gyK7SsuOHTDKzHwai5R00gs7m5+AHrh8fxb+aOyz5\\ntz9OHtBMWO8qMcdblooUcs6CqgkwPVEbZtaJBzVNDgeVHC1NklpK6294e7ZIGv8c\\nv2oAw8mMhvD4txqXW6S8oelZOKN4pcpSELTL6Kj/+L/D\\n-----END CERTIFICATE-----\\n\"\n      }\n    }\n  },\n  storageType: \"InMemoryDB\",\n  keys: {\n    privateKey: {\n      key: \"-----BEGIN PRIVATE KEY-----\\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD40tysViQSnd3E\\nIe5+6hDM/7ixHND8UoxYAKWwnA2/PdH2lq/pzjOo1t1Jt6ZbZx2l3cNUDt7FQXHL\\nvZeEn0w75/LVe/gIeoKJIUTWrXyVOrrPn50oWiaKX5pnMCLWUwk1usRwnP7o26SH\\nURTebSfBI7kQfh22aiv68qgGvo4lMWISVrWNCNej4oItLafRzvgBBD7GvJhqvPIW\\nTMFyqDzGRtVk8nYi9x3Wwp72eUW9aY/j/akPTLdU5a+uAjlQYDrPa0wkg+/2KIhx\\nGD/ffyggjvUaopzOEbnNGyBVXiOS3rQwwQnXNq+ip0xVecYVDJBlpOdQAxE77fUl\\nRrw5DzKtAgMBAAECggEASLuyf7nKX5q/2XYltfmLobDadwM6X5dtqMe/pylmp1FV\\nz6PqlgiNdzwfgU3qletFclepoieanMRtlCW+Zaj+6r/5bsgHD8tn3tfXvH0H3sNF\\nGi3JDaOUgnxBsQoUFNw+4/LNOzHZHY4ewONFm2MC7OUZUqXa35iXdIp77UTEXkBG\\nn4QdMraDW1DJUCx8nlUXHPntFN1AJANnx92Nsg6ZbhQrRRH4Lw8ydnUa3bN+Cy12\\n9secVwo2RVS8slJgW21UpkVKEdUxe0VIL2++0trMokGK219AwlQV86hzEDmVUum2\\nRIR3S0eknzvkJKspYc0tVvy/1uWnZggeJ+mNo1w4DQKBgQD/jpEpcdYJ9tHtBI3L\\ne8s2Q4QLqdVPScS5dMDCw0aE6+CQoDSr0l37tHy5hxPJT+WalhyLCvPVtj0H97NP\\nZLAoF/pgARpd3qhPM90R7/h7HgqxW/y+n1Qt/bAG+sR6n8LCcriYU+/PeUp1ugSW\\nAYipqpexeRHhbwAI6pAWBj9ZXwKBgQD5QU5q6gnzdM20WVzp3K4eevpaOt9w/OUW\\neI6o9wgVkvAo0p9irq8OM1SQlL3w3cX/YHktG9iF5oNRW6M2p7aKN1d5ZlUDhr1k\\n/ogbtqg2CTWUikac4cUlZcour589DExlpvVL3zQda5/L7Cr0RrBmKRjMb1fyPXsy\\nWJIllAgTcwKBgQDta7AlBuNJQotpXe+1+f6jHTqR82h/TxN7EKL8zpq3ZsSs2InW\\nj4xNCjNN0dZqEtZHNeqyqqw6AiLVQiTOP8cAmLY9dwjd6LwJSS+7OGxrRU+90q4P\\nEssMJ0HgWh0rpz0zlY01x9VltVOd6AHWsvoaVqizcr1P6OXpYrIWJBu6lQKBgQDS\\n5isP048v67jRzHsNdafuKmgCSKYe2ByOcttipAK3HmkOYYhy2xNLlKsM2o4Ma9nI\\nRzzAqjr+sRiTklH7QNT3BfSBx9BO94bxGVzY9ihF8Gzhjk5JF87T4di8v+SgpvNN\\nX4NV+zoBWrsOtHlzzwwapNNSxzNGyDahVsfx+9sJeQKBgFuvm70VulN5Rd4TMcF2\\nWixQNHEDStWBWPTa15ehDRIvxqfGZCkuY5o9tGY1vHxnpiHhqVheyRtLuHI6j5b3\\nil3T5+cXdt1MnmkXUksqwgwcJdMqI5fmcuO9vdeYuGV4MoXysBdKMhqPybcVIonT\\n5coMCbW92hodfPZ3F93PQpJU\\n-----END PRIVATE KEY-----\\n\"\n    },\n    publicKey: {\n      key: \"-----BEGIN CERTIFICATE-----\\nMIIDjzCCAnegAwIBAgIUNC48rSIoaMJC9YAcJ/MnfQcBmDgwDQYJKoZIhvcNAQEL\\nBQAwVjELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By\\naW5nZmllbGQxDDAKBgNVBAoMA0RpczESMBAGA1UEAwwJZGV2c2VydmVyMCAXDTIx\\nMDYwNzIwMTQzOVoYDzIxMjEwNTE0MjAxNDM5WjBWMQswCQYDVQQGEwJVUzEPMA0G\\nA1UECAwGRGVuaWFsMRQwEgYDVQQHDAtTcHJpbmdmaWVsZDEMMAoGA1UECgwDRGlz\\nMRIwEAYDVQQDDAlkZXZzZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\\nAoIBAQD40tysViQSnd3EIe5+6hDM/7ixHND8UoxYAKWwnA2/PdH2lq/pzjOo1t1J\\nt6ZbZx2l3cNUDt7FQXHLvZeEn0w75/LVe/gIeoKJIUTWrXyVOrrPn50oWiaKX5pn\\nMCLWUwk1usRwnP7o26SHURTebSfBI7kQfh22aiv68qgGvo4lMWISVrWNCNej4oIt\\nLafRzvgBBD7GvJhqvPIWTMFyqDzGRtVk8nYi9x3Wwp72eUW9aY/j/akPTLdU5a+u\\nAjlQYDrPa0wkg+/2KIhxGD/ffyggjvUaopzOEbnNGyBVXiOS3rQwwQnXNq+ip0xV\\necYVDJBlpOdQAxE77fUlRrw5DzKtAgMBAAGjUzBRMB0GA1UdDgQWBBRJRP2WG0uR\\nvDPnSRmV6Y8Rxu6ErDAfBgNVHSMEGDAWgBRJRP2WG0uRvDPnSRmV6Y8Rxu6ErDAP\\nBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDhKnZDt5VwTroWcTtX\\nLSqIDtLLHiZxk6PIE8X9DG+rU//4Rfd+MFHClcKWiyLgYZPdgPaXSDXPiyfxlb7v\\njOA0F0PXbEpR/RmjM5A+x3gljSufrWgedEC6rFFEg5Ju1IY+/7nJYkvd3ICMiLB3\\ngOczMEp/tI7m89DS+bJAGG8AIYeBjj+3OjuGdEFtXpkt1ri33LYC4wK+rjqkBMyi\\njqwex5bEkloSuyWP/IIDa8OpBWUM17H9ZswG74kQr5/wsvvTxc/JvRmMtNrbUyKa\\n2JKXA1IJgNPP4/v2FxiGTibidZVf0fyXVqarU5Ngj/fVQyn7EBg+VGqPintiL5xU\\ngUsi\\n-----END CERTIFICATE-----\\n\"\n    }\n  }\n}\n```\n\nExample: [Multi-tenant  ReactJS Application with Tenant selector](./examples/multiTenantReactJSExample)\n\n# Configuration for Cross-Tenant Application\n[Cross-tenant  ReactJS Application with Tenant selector and approval proccess](./examples/crossTenantReactJSExample)\n\n\n# Url Protection Level\n\n| Access Level | Page Handlers                 | Description                                                     |\n|--------------|-------------------------------|-----------------------------------------------------------------|\n| public       | PublicUrlPageHandler.ts       | Get resource without authentication and authorization           |\n| multi-tenant | MultiTenantUrlPageHandler.ts  | Get Multi-tenant resource with authentication and authorization |\n| single       | SingleTenantUrlPageHandler.ts | Default Tenant authentication and authorization                 |\n\n- default public urls\n   |              Public Urls                  |\n   |-------------------------------------------|\n   | (.*)(/public)(.*)                         |\n   | (.*)(.(jpg \\| jpeg \\| png \\| gif \\| bmp)) |\n   | (.*)(.(ico \\| tiff))                      |\n   | (.* )(.(css))                             |\n\n- default tenant urls\n\n   |              Single tenant Urls           |\n   |-------------------------------------------|\n   | /                                         |\n   | /index.html                               |\n\n# Custom Page Handlers\n\n- Existing page handlers\n\n| Page Handler               | Description                                                                                                                                                         |\n|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| PublicUrlPageHandler       | Handler for public web resources                                                                                                                                    |\n| SingleTenantUrlPageHandler | Handler for default tenant web resources                                                                                                                             |\n| MultiTenantUrlPageHandler  | Handler for multi-tenant web resources                                                                                                                              |\n| TokenPageHandler           | Handler for /token path.  Return single tenant access_token if use single tenant authentication Return multi-tenant access_token if use multi-tenant authentication |\n| TenantInternalPage         | Internal Tenant selector. If open /tenants/\u003cREALM NAME\u003e then redirect to \u003cREALM NAME\u003e login page                                                                    |\n| TenantExternalPage         | External Tenant selector. Redirect to external Service to select tenant.                                                                                            |\n\n- Add Custom Page Handler\n```js\nconst keycloakApiGateWayAdapter = new adapter.KeycloakApiGateWayAdapter(\n    options\n)\n    .addCustomPageHandler(new PublicUrlPageHandler('icon.ico', 15000));\n```\n\n- Delete custom Page Handler\n```js\nconst keycloakApiGateWayAdapter = new adapter.KeycloakApiGateWayAdapter(\n    options\n)\n    .deleteCustomPageHandler('icon.ico');\n```\n\n- Replace custom Page Handler\n\n```\nconst keycloakApiGateWayAdapter = new adapter.KeycloakApiGateWayAdapter(\n    options\n)\n    .addCustomPageHandler(new TenantExternalPage(\"/\", {\n        redirectedUrl: \"http://localhost:8082\",\n        applicationName: 'multiTenantreactJsExample'\n    }, 0))\n    .addCustomPageHandler(new TenantExternalPage(\"/index.html\", {\n        redirectedUrl: \"http://localhost:8082\",\n        applicationName: 'multiTenantreactJsExample'\n    }, 32000))\n```\n\n# KeycloakApiGateWayAdapter OPTIONS\n\n```js\n    multiTenantJson: (tenant: string)=\u003e{\n           return KeycloakJSONForTenant(tenant)\n    };\n    multiTenantAdapterOptions: {...};\n    defaultAdapterOptions: {\n        keycloakJson,\n        ...\n    }\n    storageType: 'DynamoDB',\n    identityProviders: {\n        \"multiTenant\":\"IdentityProvider Alias\",\n        \"singleTenant\":\"IdentityProvider Alias\"\n      },\n    storageTypeSettings: {\n        tableName,\n        region,\n        apiVersion,\n    }\n    keys: RSA KEYS,\n```\nwhere\n - **defaultAdapterOptions** authentication and authorization for single-tenant application ([structure](https://github.com/vzakharchenko/keycloak-lambda-authorizer#option-structure))\n - **multiTenantAdapterOptions** authentication and authorization for multi-tenant application ([structure](https://github.com/vzakharchenko/keycloak-lambda-authorizer#option-structure))\n - **multiTenantJson** tenant Keycloak.json resolver\n - **storageType** place where store session data(user access and refresh tokens)\n    - DynamoDB store in AWS DynamoDB\n    - InMemoryDB store in file\n    - own implementation of StorageDB ([example](./examples/customStorageExample))\n - **identityProviders** Identity Provider Alias name.\n    - multiTenant - Identity Provider for Multitenant application. need use the same alias name between tenants. can be overridden by request parameter kc_idp_hint\n    - singleTenant - Identity Provider for application.\n - **storageTypeSettings** configuration for storageType\n - keys RSA keys which can be used for sign/verify sessionId and also can be used for \"Signed JWT\" client authentication\n\n```js\nconst keycloakApiGateWayAdapter = new KeycloakApiGateWayAdapter(\n{\n  \"defaultAdapterOptions\": AUTHENTICATION AND AUTHORIZATION OPTIONS,\n  \"storageType\": \"InMemoryDB\",\n  \"keys\": {\n    \"privateKey\": {\n      \"key\": PRIVATE KEY\n    },\n    \"publicKey\": {\n      \"key\": CERTIFICATE OR PUBLIC KEY\n    }\n  }\n}\n);\n```\n#  **[AWS Lambda@edge](https://aws.amazon.com/ru/lambda/edge/) middleWare**\n\n```js\nmodule.exports.handler =\n    async (awsEvent) =\u003e {\n      return await keycloakApiGateWayAdapter\n            .awsLambdaEdgeAdapter()\n            .handler(awsEvent);\n    };\n\n```\n\n# **[ExpressJS](https://www.npmjs.com/package/express) Server**\n\n```js\nconst middlewareServer = express();\nmiddlewareServer.use(cookieParser());\nmiddlewareServer.use(async (req, res, next) =\u003e {\n  await keycloakApiGateWayAdapter.expressMiddleWare().middleWare(req, res, next);\n});\nmiddlewareServer.use(express.static('./static'));\n\nmiddlewareServer.listen(8080, () =\u003e {\n  console.info('HTTP server listening on port 8080');\n});\n```\n\n# **[https://www.npmjs.com/package/@craco/craco](https://www.npmjs.com/package/@craco/craco) Development Server**\n[craco.config.js](./development/craco.config.js)\n```js\n\nmodule.exports = {\n    devServer: (devServerConfig) =\u003e {\n        keycloakApiGateWayAdapter.webPackDevServerMiddleWare().applyMiddleWare(devServerConfig);\n        return devServerConfig;\n    }\n};\n```\n\n# **[Webpack](https://www.npmjs.com/package/webpack) Development Server**\n\n```js\n\nconst config = {\n    mode: env,\n    ...,\n    devServer:{},\n    ...\n};\nkeycloakApiGateWayAdapter\n  .webPackDevServerMiddleWare()\n  .applyMiddleWare(config.devServer);\n\nmodule.exports = config;\n```\n\n# Session Token RSA Keys Generation\n```\nopenssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj \"/C=US/ST=Denial/L=Springfield/O=Dis/CN=clientId\" -keyout server.key -out server.crt\n```\n# Signed JWT Token RSA Generation\n```\nopenssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj \"/C=US/ST=Denial/L=Springfield/O=Dis/CN=clientId\" -keyout server.key -out server.crt\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvzakharchenko%2Fkeycloak-api-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvzakharchenko%2Fkeycloak-api-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvzakharchenko%2Fkeycloak-api-gateway/lists"}