diff --git a/package-lock.json b/package-lock.json
index 2542e79325..523163262c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,6 +33,10 @@
"typedoc-plugin-markdown": "3.14.0"
}
},
+ "node_modules/-auth": {
+ "resolved": "sandbox/oauth-example",
+ "link": true
+ },
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -11175,10 +11179,6 @@
"resolved": "sandbox/notification-socket-example",
"link": true
},
- "node_modules/@sourceloop/oauth-example-api": {
- "resolved": "sandbox/oauth-example",
- "link": true
- },
"node_modules/@sourceloop/oidc-basic-example": {
"resolved": "sandbox/oidc-basic-example",
"link": true
@@ -44405,37 +44405,275 @@
}
},
"sandbox/oauth-example": {
- "name": "@sourceloop/oauth-example-api",
- "version": "0.5.13",
+ "name": "-auth",
+ "version": "0.0.1",
"license": "MIT",
"dependencies": {
"@loopback/boot": "^7.0.9",
+ "@loopback/context": "^7.0.9",
"@loopback/core": "^6.1.6",
+ "@loopback/openapi-v3": "^10.0.9",
"@loopback/repository": "^7.0.9",
"@loopback/rest": "^14.0.9",
"@loopback/rest-explorer": "^7.0.9",
"@loopback/service-proxy": "^7.0.9",
+ "@opentelemetry/exporter-jaeger": "^1.15.0",
+ "@opentelemetry/plugin-dns": "^0.15.0",
+ "@opentelemetry/plugin-http": "^0.18.2",
+ "@opentelemetry/plugin-https": "^0.18.2",
+ "@opentelemetry/plugin-pg": "^0.15.0",
+ "@opentelemetry/plugin-pg-pool": "^0.15.0",
+ "@opentelemetry/sdk-trace-base": "^1.15.0",
+ "@opentelemetry/sdk-trace-node": "^1.15.0",
"@sourceloop/authentication-service": "^20.0.2",
- "bcrypt": "^5.0.1",
+ "@sourceloop/core": "^15.0.2",
"db-migrate": "^1.0.0-beta.21",
"db-migrate-pg": "^1.3.0",
"dotenv": "^16.4.5",
"dotenv-extended": "^2.9.0",
+ "loopback-connector-kv-redis": "^4.0.0",
"loopback-connector-postgresql": "^7.1.8",
+ "loopback4-authentication": "^12.1.1",
+ "loopback4-authorization": "^7.0.3",
+ "swagger-stats": "^0.99.5",
+ "symlink-resolver": "0.2.1",
"tslib": "^2.6.2"
},
"devDependencies": {
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
"@loopback/build": "^11.0.8",
"@loopback/eslint-config": "^15.0.4",
"@loopback/testlab": "^7.0.8",
- "@types/bcrypt": "^5.0.0",
"@types/node": "^20.12.7",
"eslint": "^8.57.0",
+ "nodemon": "^2.0.21",
+ "nyc": "^15.1.0",
"source-map-support": "^0.5.21",
"typescript": "^5.4.5"
},
"engines": {
- "node": "18 || 20"
+ "node": ">=18"
+ }
+ },
+ "sandbox/oauth-example/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "sandbox/oauth-example/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "sandbox/oauth-example/node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "sandbox/oauth-example/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/foreground-child": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
+ "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "sandbox/oauth-example/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "sandbox/oauth-example/node_modules/istanbul-lib-instrument": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+ "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.7.5",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.0.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "sandbox/oauth-example/node_modules/nyc": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
+ "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
+ "dev": true,
+ "dependencies": {
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "caching-transform": "^4.0.0",
+ "convert-source-map": "^1.7.0",
+ "decamelize": "^1.2.0",
+ "find-cache-dir": "^3.2.0",
+ "find-up": "^4.1.0",
+ "foreground-child": "^2.0.0",
+ "get-package-type": "^0.1.0",
+ "glob": "^7.1.6",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-hook": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "istanbul-lib-processinfo": "^2.0.2",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.2",
+ "make-dir": "^3.0.0",
+ "node-preload": "^0.2.1",
+ "p-map": "^3.0.0",
+ "process-on-spawn": "^1.0.0",
+ "resolve-from": "^5.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "spawn-wrap": "^2.0.0",
+ "test-exclude": "^6.0.0",
+ "yargs": "^15.0.2"
+ },
+ "bin": {
+ "nyc": "bin/nyc.js"
+ },
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
+ "sandbox/oauth-example/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "sandbox/oauth-example/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/p-map": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
+ "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
+ "dev": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "sandbox/oauth-example/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
}
},
"sandbox/oauth-example/node_modules/typescript": {
@@ -44451,6 +44689,61 @@
"node": ">=14.17"
}
},
+ "sandbox/oauth-example/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true
+ },
+ "sandbox/oauth-example/node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "sandbox/oauth-example/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"sandbox/oidc-basic-example": {
"name": "@sourceloop/oidc-basic-example",
"version": "0.4.9",
diff --git a/packages/cli/README.md b/packages/cli/README.md
index 250126b983..93d860fc6e 100644
--- a/packages/cli/README.md
+++ b/packages/cli/README.md
@@ -18,7 +18,7 @@ $ npm install -g @sourceloop/cli
$ sl COMMAND
running command...
$ sl (-v|--version|version)
-@sourceloop/cli/9.2.3 linux-x64 node-v18.20.5
+@sourceloop/cli/9.2.3 linux-x64 node-v18.18.2
$ sl --help [COMMAND]
USAGE
$ sl COMMAND
diff --git a/sandbox/auth-ms-basic-example/package.json b/sandbox/auth-ms-basic-example/package.json
index 4b5fcade71..c35e587d00 100644
--- a/sandbox/auth-ms-basic-example/package.json
+++ b/sandbox/auth-ms-basic-example/package.json
@@ -92,4 +92,4 @@
"lodash": "^4.17.21"
}
}
-}
+}
\ No newline at end of file
diff --git a/sandbox/oauth-example/.dockerignore b/sandbox/oauth-example/.dockerignore
index 7aecc7e3dd..86e2a5ca75 100644
--- a/sandbox/oauth-example/.dockerignore
+++ b/sandbox/oauth-example/.dockerignore
@@ -1,5 +1,6 @@
-node_modules
+coverage
npm-debug.log
/dist
# Cache used by TypeScript's incremental build
*.tsbuildinfo
+mochawesome-report
\ No newline at end of file
diff --git a/sandbox/oauth-example/.env.defaults b/sandbox/oauth-example/.env.defaults
new file mode 100644
index 0000000000..9be445332f
--- /dev/null
+++ b/sandbox/oauth-example/.env.defaults
@@ -0,0 +1,66 @@
+NODE_ENV=production
+LOG_LEVEL=info
+USER_TEMP_PASSWORD=temp123!@
+GOOGLE_AUTH_URL=q
+GOOGLE_AUTH_CLIENT_ID=a
+GOOGLE_AUTH_CLIENT_SECRET=q
+GOOGLE_AUTH_TOKEN_URL=q
+GOOGLE_AUTH_CALLBACK_URL=q
+GOOGLE_TOKEN_INFO_URL=q
+INSTAGRAM_AUTH_URL=q
+INSTAGRAM_AUTH_CLIENT_ID=a
+INSTAGRAM_AUTH_CLIENT_SECRET=q
+INSTAGRAM_AUTH_TOKEN_URL=q
+INSTAGRAM_AUTH_CALLBACK_URL=q
+SAML_URL=q
+SAML_CLIENT_ID=a
+SAML_CLIENT_SECRET=q
+SAML_TOKEN_URL=q
+SAML_CALLBACK_URL=q
+APPLE_AUTH_URL=q
+APPLE_AUTH_CLIENT_ID=a
+APPLE_AUTH_TEAM_ID=q
+APPLE_AUTH_KEY_ID=q
+APPLE_AUTH_CALLBACK_URL=q
+FACEBOOK_AUTH_URL=q
+FACEBOOK_AUTH_CLIENT_ID=a
+FACEBOOK_AUTH_CLIENT_SECRET=q
+FACEBOOK_AUTH_TOKEN_URL=q
+FACEBOOK_AUTH_CALLBACK_URL=q
+REDIS_PORT=a
+REDIS_HOST=a
+REDIS_URL=
+REDIS_PASSWORD=a
+REDIS_DATABASE=a
+FORGOT_PASSWORD_LINK_EXPIRY=30
+REQUEST_SIGNUP_LINK_EXPIRY=30
+
+# AZURE AD
+#boolean values will be 0 or 1
+
+AZURE_AUTH_ENABLED=0
+AZURE_IDENTITY_METADATA=https://login.microsoftonline.com/common/.well-known/openid-configuration
+AZURE_AUTH_CLIENT_ID=a
+AZURE_AUTH_REDIRECT_URL=url
+AZURE_AUTH_CLIENT_SECRET=client_secret
+AZURE_AUTH_ALLOW_HTTP_REDIRECT=1
+AZURE_AUTH_COOKIE_INSTEAD_SESSION=1
+AZURE_AUTH_PASS_REQ_CALLBACK=0
+AZURE_AUTH_VALIDATE_ISSUER=0
+AZURE_AUTH_B2C_TENANT=0
+AZURE_AUTH_CLOCK_SKEW=300
+AZURE_AUTH_LOG_LEVEL=
+AZURE_AUTH_LOG_PII=1
+AZURE_AUTH_NONCE_TIME=3600
+AZURE_AUTH_NONCE_COUNT=10
+AZURE_AUTH_ISSUER=
+
+# key is 32 bit
+
+AZURE_AUTH_COOKIE_KEY=
+
+#iv is 12 bit
+
+AZURE_AUTH_COOKIE_IV=
+
+MAX_JWT_KEYS=2
diff --git a/sandbox/oauth-example/.env.example b/sandbox/oauth-example/.env.example
new file mode 100644
index 0000000000..fc4607c679
--- /dev/null
+++ b/sandbox/oauth-example/.env.example
@@ -0,0 +1,87 @@
+NODE_ENV=
+LOG_LEVEL=
+DB_HOST=
+DB_PORT=
+DB_USER=
+DB_PASSWORD=
+DB_DATABASE=
+DB_SCHEMA=
+REDIS_HOST=
+REDIS_PORT=
+REDIS_URL=
+REDIS_PASSWORD=
+REDIS_DATABASE=
+# PRIVATE_DECRYPTION_KEY=
+JWT_SECRET=
+JWT_ISSUER=
+# USER_TEMP_PASSWORD=
+GOOGLE_AUTH_URL=
+GOOGLE_AUTH_CLIENT_ID=
+GOOGLE_AUTH_CLIENT_SECRET=
+GOOGLE_AUTH_TOKEN_URL=
+GOOGLE_AUTH_CALLBACK_URL=
+# GOOGLE_TOKEN_INFO_URL=
+# SAML_URL=
+# SAML_CLIENT_ID=
+# SAML_CLIENT_SECRET=
+# SAML_TOKEN_URL=
+# SAML_CALLBACK_URL=
+# INSTAGRAM_AUTH_URL=
+# INSTAGRAM_AUTH_CLIENT_ID=
+# INSTAGRAM_AUTH_CLIENT_SECRET=
+# INSTAGRAM_AUTH_TOKEN_URL=
+# INSTAGRAM_AUTH_CALLBACK_URL=
+# APPLE_AUTH_URL=
+# APPLE_AUTH_CLIENT_ID=
+# APPLE_AUTH_TEAM_ID=
+# APPLE_AUTH_KEY_ID=
+# APPLE_AUTH_CALLBACK_URL=
+# FACEBOOK_AUTH_URL=
+# FACEBOOK_AUTH_CLIENT_ID=
+# FACEBOOK_AUTH_CLIENT_SECRET=
+# FACEBOOK_AUTH_TOKEN_URL=
+# FACEBOOK_AUTH_CALLBACK_URL=
+# FORGOT_PASSWORD_LINK_EXPIRY=
+# KEYCLOAK_HOST=
+# KEYCLOAK_REALM=
+# KEYCLOAK_CLIENT_ID=
+# KEYCLOAK_CLIENT_SECRET=
+# KEYCLOAK_CALLBACK_URL=
+
+# # AZURE AD
+# #boolean values will be 0 or 1
+
+# AZURE_AUTH_ENABLED=
+# AZURE_IDENTITY_METADATA=
+# AZURE_AUTH_CLIENT_ID=
+# AZURE_AUTH_REDIRECT_URL=
+# AZURE_AUTH_CLIENT_SECRET=
+# AZURE_AUTH_ALLOW_HTTP_REDIRECT=
+# AZURE_AUTH_COOKIE_INSTEAD_SESSION=
+# AZURE_AUTH_PASS_REQ_CALLBACK=
+# AZURE_AUTH_VALIDATE_ISSUER=
+# AZURE_AUTH_B2C_TENANT=
+# AZURE_AUTH_CLOCK_SKEW=
+# AZURE_AUTH_LOG_LEVEL=
+# AZURE_AUTH_LOG_PII=
+# AZURE_AUTH_NONCE_TIME=
+# AZURE_AUTH_NONCE_COUNT=
+# AZURE_AUTH_ISSUER=
+
+# # key is 32 bit
+
+# AZURE_AUTH_COOKIE_KEY=
+
+# #iv is 12 bit
+
+# AZURE_AUTH_COOKIE_IV=
+
+
+# AUTH0_DOMAIN=
+# AUTH0_CLIENT_ID=
+# AUTH0_CLIENT_SECRET=
+# AUTH0_CALLBACK_URL=
+
+# MAX_JWT_KEYS=
+# JWT_PRIVATE_KEY_PASSPHRASE=
+# API_BASE_URL=
diff --git a/sandbox/oauth-example/.eslintignore b/sandbox/oauth-example/.eslintignore
index 51b39e3ec0..e300953d30 100644
--- a/sandbox/oauth-example/.eslintignore
+++ b/sandbox/oauth-example/.eslintignore
@@ -2,4 +2,5 @@ node_modules/
dist/
coverage/
migrations/
-.eslintrc.js
+migration.js
+.eslintrc.js
\ No newline at end of file
diff --git a/sandbox/oauth-example/.eslintrc.js b/sandbox/oauth-example/.eslintrc.js
index 978b9dcca2..aef13fa415 100644
--- a/sandbox/oauth-example/.eslintrc.js
+++ b/sandbox/oauth-example/.eslintrc.js
@@ -1,3 +1,13 @@
module.exports = {
extends: '@loopback/eslint-config',
+ rules: {
+ 'no-extra-boolean-cast': 'off',
+ '@typescript-eslint/interface-name-prefix': 'off',
+ 'no-prototype-builtins': 'off',
+ 'no-await-in-loop': 'error',
+ },
+ parserOptions: {
+ project: './tsconfig.json',
+ tsconfigRootDir: __dirname,
+ },
};
diff --git a/sandbox/oauth-example/.mocharc.json b/sandbox/oauth-example/.mocharc.json
index 7b523c3163..a141fff9d2 100644
--- a/sandbox/oauth-example/.mocharc.json
+++ b/sandbox/oauth-example/.mocharc.json
@@ -1,5 +1,6 @@
{
"exit": true,
"recursive": true,
- "require": "source-map-support/register"
+ "require": "source-map-support/register",
+ "reporter": "mochawesome"
}
diff --git a/sandbox/oauth-example/.nycrc b/sandbox/oauth-example/.nycrc
new file mode 100644
index 0000000000..115a4e397c
--- /dev/null
+++ b/sandbox/oauth-example/.nycrc
@@ -0,0 +1,5 @@
+{
+ "extends": "@istanbuljs/nyc-config-typescript",
+ "all": true,
+ "reporter": ["html", "text-summary"]
+}
\ No newline at end of file
diff --git a/sandbox/oauth-example/.prettierignore b/sandbox/oauth-example/.prettierignore
index c6911da9e1..3f725726d0 100644
--- a/sandbox/oauth-example/.prettierignore
+++ b/sandbox/oauth-example/.prettierignore
@@ -1,2 +1,5 @@
dist
*.json
+coverage
+mochawesome-report
+node_modules/
\ No newline at end of file
diff --git a/sandbox/oauth-example/.vscode/settings.json b/sandbox/oauth-example/.vscode/settings.json
index 07313667ec..fa3c3aea67 100644
--- a/sandbox/oauth-example/.vscode/settings.json
+++ b/sandbox/oauth-example/.vscode/settings.json
@@ -5,8 +5,8 @@
"editor.trimAutoWhitespace": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
- "source.organizeImports": true,
- "source.fixAll.eslint": true
+ "source.organizeImports": "explicit",
+ "source.fixAll.eslint": "explicit"
},
"files.exclude": {
@@ -15,7 +15,7 @@
"**/.hg": true,
"**/.svn": true,
"**/CVS": true,
- "dist": true,
+ "dist": true
},
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
@@ -25,8 +25,5 @@
"typescript.preferences.quoteStyle": "single",
"eslint.run": "onSave",
"eslint.nodePath": "./node_modules",
- "eslint.validate": [
- "javascript",
- "typescript"
- ]
+ "eslint.validate": ["javascript", "typescript"]
}
diff --git a/sandbox/oauth-example/.yo-rc.json b/sandbox/oauth-example/.yo-rc.json
index a464128411..d4a996bdbb 100644
--- a/sandbox/oauth-example/.yo-rc.json
+++ b/sandbox/oauth-example/.yo-rc.json
@@ -1,6 +1,6 @@
{
- "@loopback/cli": {
+ "@sourceloop/cli": {
"packageManager": "npm",
- "version": "4.1.0"
+ "version": "5.2.4"
}
}
diff --git a/sandbox/oauth-example/CHANGELOG.md b/sandbox/oauth-example/CHANGELOG.md
deleted file mode 100644
index 92dc1b2c86..0000000000
--- a/sandbox/oauth-example/CHANGELOG.md
+++ /dev/null
@@ -1,492 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 0.5.13 (2025-01-07)
-
-* chore(deps): version update (#2227) ([6d6b00e](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/6d6b00e)), closes [#2227](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2227)
-
-
-
-
-
-## 0.5.12 (2024-12-20)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.11 (2024-12-05)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.10 (2024-11-22)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.9 (2024-10-22)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.8 (2024-10-16)
-
-* chore(ci-cd): resolve sonar issues (#2179) ([12ec556](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/12ec556)), closes [#2179](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2179) [#2177](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2177) [#2177](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2177)
-* chore(ci-cd): resolve sonar issues (#2180) ([19c969b](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/19c969b)), closes [#2180](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2180) [#2177](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2177)
-
-
-
-
-
-## 0.5.7 (2024-09-30)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.6 (2024-09-30)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.5 (2024-09-26)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.4 (2024-08-05)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.3 (2024-06-11)
-
-* chore: publish release ([89d1599](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/89d1599))
-* chore(deps): version update in sandbox (#2109) ([615d7f5](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/615d7f5)), closes [#2109](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2109) [#2104](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2104) [#2104](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2104)
-* chore(deps): version bump commit (#2111) ([c87bc75](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/c87bc75)), closes [#2111](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2111) [#00](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/00)
-* fix(all-services): revert to pr 2072 (#2106) ([502812f](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/502812f)), closes [#2106](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2106) [#0](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/0) [#0](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/0)
-
-
-
-
-
-## 0.5.2 (2024-06-10)
-
-* fix(all-services): revert to pr 2072 (#2106) ([502812f](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/502812f)), closes [#2106](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2106) [#0](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/0) [#0](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/0)
-
-
-
-
-
-## 0.5.1 (2024-06-04)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.5.0 (2024-05-20)
-
-* feat(all-services): Follow solid for repositories in all services (#2072) ([82c934b](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/82c934b)), closes [#2072](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2072) [#2037](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2037)
-
-
-
-
-
-## 0.4.4 (2024-05-07)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.4.3 (2024-04-05)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.4.2 (2024-04-02)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.4.1 (2024-03-26)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.4.0 (2024-03-20)
-
-* feat(authentication-service): added SAML example (#1912) ([72002ac](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/72002ac)), closes [#1912](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1912) [#1663](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1663) [#1663](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1663)
-
-
-### BREAKING CHANGE
-
-*
-
-
-
-
-## 0.3.12 (2024-03-12)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.11 (2024-03-06)
-
-* fix(all-services): fix sonar issues in all services (#2018) ([33dfa77](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/33dfa77)), closes [#2018](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2018) [#2013](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2013)
-* fix(all-services): fix the pending sonar issues in all services (#2025) ([b2f6dc3](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/b2f6dc3)), closes [#2025](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2025) [#2013](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/2013)
-* chore(deps): update versions in sandbox and fix vulnerabilities (#1941) ([5e37add](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/5e37add)), closes [#1941](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1941) [#1934](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1934)
-
-
-
-
-
-## 0.3.10 (2024-02-02)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.9 (2024-02-01)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.8 (2024-01-23)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.7 (2024-01-19)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.6 (2024-01-09)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.5 (2024-01-01)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.4 (2024-01-01)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.3 (2023-12-22)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.2 (2023-12-07)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.1 (2023-12-07)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.3.0 (2023-11-09)
-
-* feat(chore): migrate to use npm workspaces (#1684) ([72d8f6e](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/72d8f6e)), closes [#1684](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1684) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673) [#1673](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1673)
-
-
-### BREAKING CHANGE
-
-* lerna bootstrap command will not be supported
-* lerna bootstrap command will not be supported
-* lerna bootstrap command will not be supported
-* lerna bootstrap will not be supported
-* lerna bootstrap will not be supported
-
-
-
-
-## 0.2.25 (2023-10-19)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.24 (2023-10-05)
-
-* refactor(all-services): remove redundant `posttest` script (#1677) ([4b252cf](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/4b252cf)), closes [#1677](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1677) [#1657](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1657)
-
-
-
-
-
-## 0.2.23 (2023-09-01)
-
-* refactor(all-services): fix sonar code smells (#1602) ([51f1cc3](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/51f1cc3)), closes [#1602](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1602)
-
-
-
-
-
-## 0.2.22 (2023-08-10)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.21 (2023-08-09)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.20 (2023-07-28)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.19 (2023-07-18)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.18 (2023-07-11)
-
-* chore(deps): combine dependabot updates (#1474) ([c333a9c](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/c333a9c)), closes [#1474](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1474)
-* chore(deps): combine snyk updates (#1480) ([ef93ac6](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/ef93ac6)), closes [#1480](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1480)
-* chore(deps): package lock upgrade (#1519) ([5aaddbf](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/5aaddbf)), closes [#1519](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1519)
-
-
-
-
-
-## 0.2.17 (2023-06-19)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.16 (2023-06-10)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.15 (2023-06-08)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.14 (2023-06-08)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.13 (2023-06-07)
-
-* refactor(all-services): remove empty and unnecessary folder (#1423) ([15c8235](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/15c8235)), closes [#1423](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1423)
-
-
-
-
-
-## 0.2.12 (2023-05-11)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.11 (2023-05-03)
-
-* chore(all-services): update license and copyright headers (#1405) ([7493640](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/7493640)), closes [#1405](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1405)
-
-
-
-
-
-## 0.2.10 (2023-04-27)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.9 (2023-04-10)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.8 (2023-03-15)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.7 (2023-03-06)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.6 (2023-02-01)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.5 (2023-01-31)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.4 (2023-01-20)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.3 (2023-01-17)
-
-* fix(authentication-service): fix sql syntax in migrations. (#1205) ([2a1298b](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/2a1298b)), closes [#1205](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1205) [#1204](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1204) [#1204](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1204)
-
-
-
-
-
-## 0.2.2 (2023-01-12)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.1 (2022-12-07)
-
-**Note:** Version bump only for package @sourceloop/oauth-example-api
-
-
-
-
-
-## 0.2.0 (2022-11-25)
-
-* feat(authentication-service): feat(authentication-service): change parent class AuthClient (#1081) ([537cc75](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/537cc75)), closes [#1081](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1081)
-
-
-
-
-
-## 0.1.0 (2022-10-17)
-
-* feat(sandbox): add oAuth-example with ui (#1008) ([2c990dc](https://github.com/sourcefuse/loopback4-microservice-catalog/commit/2c990dc)), closes [#1008](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/1008) [#993](https://github.com/sourcefuse/loopback4-microservice-catalog/issues/993)
diff --git a/sandbox/oauth-example/Dockerfile b/sandbox/oauth-example/Dockerfile
index 320047513d..17580fe640 100644
--- a/sandbox/oauth-example/Dockerfile
+++ b/sandbox/oauth-example/Dockerfile
@@ -1,5 +1,23 @@
# Check out https://hub.docker.com/_/node to select a new base image
-FROM node:lts-slim
+ARG nodeVer=18-alpine
+
+# select a base image to build from
+FROM node:$nodeVer AS BASE
+
+# Take the build variables for image base
+ARG SERVICE_NAME
+ARG FROM_FOLDER
+# This command is used to install some dependencies in the Docker image.
+# Nessasary for running node-prune and npm install
+RUN apk update && apk add --no-cache --virtual .gyp \
+ python3 \
+ make \
+ g++ \
+ bash \
+ curl
+
+# This is used to download and install the `node-prune` tool in the Docker image.
+RUN curl -sfL https://gobinaries.com/tj/node-prune | bash -s -- -b /usr/local/bin
# Set to a non-root built-in user `node`
USER node
@@ -7,6 +25,7 @@ USER node
# Create app directory (with user `node`)
RUN mkdir -p /home/node/app
+# Set the working directory to `/home/node/app`
WORKDIR /home/node/app
# Install app dependencies
@@ -14,15 +33,56 @@ WORKDIR /home/node/app
# where available (npm@5+)
COPY --chown=node package*.json ./
-RUN npm ci
+# The following two commands is used to copy the `packages`,`service` directory from the local file system to the Docker image.
+# The `--chown=node` flag ensures that the ownership of the copied files/directories is set to the `node` user.
+# This is important because the subsequent commands in the Dockerfile are executed with the `node` user,
+# and it needs the appropriate permissions to access and modify the copied files/directories.
+COPY --chown=node packages ./packages
-# Bundle app source code
-COPY --chown=node . .
+COPY --chown=node $FROM_FOLDER/$SERVICE_NAME ./$FROM_FOLDER/$SERVICE_NAME
+# Installing all dependencies
+RUN npm install
+
+# Building the app
+# set the Working Directory to the service
+WORKDIR /home/node/app/$FROM_FOLDER/$SERVICE_NAME
+# Run Build Command
RUN npm run build
+# Run node-prune
+RUN npm prune --production
+RUN /usr/local/bin/node-prune
+
+# Start fresh for a smaller image size
+FROM node:$nodeVer
+
+# Take the build variables for image stage
+ARG SERVICE_NAME
+ARG FROM_FOLDER
+
+RUN mkdir -p /home/node/app
+
+USER node
+
+WORKDIR /home/node/app
+
+
+# These `COPY` commands are used to copy files and directories from the `BASE`
+# stage of the Docker image to the current stage.
+COPY --from=BASE --chown=node /home/node/app/node_modules ./node_modules
+COPY --from=BASE --chown=node /home/node/app/package.json ./
+COPY --from=BASE --chown=node /home/node/app/package-lock.json ./
+COPY --from=BASE --chown=node /home/node/app/packages ./packages
+COPY --from=BASE --chown=node /home/node/app/$FROM_FOLDER/$SERVICE_NAME ./$FROM_FOLDER/$SERVICE_NAME
+
+# Set the working directory to `/home/node/app/services/auth-service`
+WORKDIR /home/node/app/$FROM_FOLDER/$SERVICE_NAME
+
+
# Bind to all network interfaces so that it can be mapped to the host OS
ENV HOST=0.0.0.0 PORT=3000
EXPOSE ${PORT}
-CMD [ "node", "." ]
+
+CMD [ "node", "." ]
\ No newline at end of file
diff --git a/sandbox/oauth-example/README.md b/sandbox/oauth-example/README.md
index 8bb67b6509..80e4d61385 100644
--- a/sandbox/oauth-example/README.md
+++ b/sandbox/oauth-example/README.md
@@ -1,4 +1,4 @@
-# auth-service
+# auth
This application is generated using [LoopBack 4 CLI](https://loopback.io/doc/en/lb4/Command-line-interface.html) with the
[initial project layout](https://loopback.io/doc/en/lb4/Loopback-application-layout.html).
diff --git a/sandbox/oauth-example/database.json b/sandbox/oauth-example/database.json
deleted file mode 100644
index cf1880315e..0000000000
--- a/sandbox/oauth-example/database.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "defaultEnv": "local",
- "local": {
- "driver": "pg",
- "host": {
- "ENV": "DB_HOST"
- },
- "port": {
- "ENV": "DB_PORT"
- },
- "user": {
- "ENV": "DB_USER"
- },
- "password": {
- "ENV": "DB_PASSWORD"
- },
- "database": {
- "ENV": "DB_DATABASE"
- }
- }
- }
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/20210421113036-init.js b/sandbox/oauth-example/migrations/20210318100600-init.js
similarity index 77%
rename from sandbox/oauth-example/migrations/20210421113036-init.js
rename to sandbox/oauth-example/migrations/20210318100600-init.js
index 4faf7411cb..f7aa1b04c5 100644
--- a/sandbox/oauth-example/migrations/20210421113036-init.js
+++ b/sandbox/oauth-example/migrations/20210318100600-init.js
@@ -5,16 +5,8 @@ var type;
var seed;
var fs = require('fs');
var path = require('path');
-var Promise;
-
-function handleFile(filePath, resolve, reject) {
- fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
- if (err) return reject(err);
- console.log('received data: ' + data);
- resolve(data);
- });
-}
+var Promise;
/**
* We receive the dbmigrate dependency from dbmigrate initially.
@@ -28,23 +20,32 @@ exports.setup = function (options, seedLink) {
};
exports.up = function (db) {
- var filePath = path.join(__dirname, 'sqls', '20210421113036-init-up.sql');
+ var filePath = path.join(__dirname, 'sqls', '20210318100600-init-up.sql');
return new Promise(function (resolve, reject) {
- handleFile(filePath, resolve, reject);
+ receiveData(resolve, reject, filePath);
}).then(function (data) {
return db.runSql(data);
});
};
exports.down = function (db) {
- var filePath = path.join(__dirname, 'sqls', '20210421113036-init-down.sql');
+ var filePath = path.join(__dirname, 'sqls', '20210318100600-init-down.sql');
return new Promise(function (resolve, reject) {
- handleFile(filePath, resolve, reject);
+ receiveData(resolve, reject, filePath);
}).then(function (data) {
return db.runSql(data);
});
};
+function receiveData(resolve, reject, filePath) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+}
+
exports._meta = {
version: 1,
};
diff --git a/sandbox/oauth-example/migrations/20221123082900-updated-init.js b/sandbox/oauth-example/migrations/20221110095658-updated-init.js
similarity index 93%
rename from sandbox/oauth-example/migrations/20221123082900-updated-init.js
rename to sandbox/oauth-example/migrations/20221110095658-updated-init.js
index 7509afe9ab..250582cb55 100644
--- a/sandbox/oauth-example/migrations/20221123082900-updated-init.js
+++ b/sandbox/oauth-example/migrations/20221110095658-updated-init.js
@@ -22,7 +22,7 @@ exports.up = function (db) {
var filePath = path.join(
__dirname,
'sqls',
- '20221123082900-updated-init-up.sql',
+ '20221110095658-updated-init-up.sql',
);
return new Promise(function (resolve, reject) {
fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
@@ -40,7 +40,7 @@ exports.down = function (db) {
var filePath = path.join(
__dirname,
'sqls',
- '20221123082900-updated-init-down.sql',
+ '20221110095658-updated-init-down.sql',
);
return new Promise(function (resolve, reject) {
fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
diff --git a/sandbox/oauth-example/migrations/20230323132703-client-type-column.js b/sandbox/oauth-example/migrations/20230323132703-client-type-column.js
new file mode 100644
index 0000000000..2608f6e0f0
--- /dev/null
+++ b/sandbox/oauth-example/migrations/20230323132703-client-type-column.js
@@ -0,0 +1,59 @@
+'use strict';
+
+var dbm;
+var type;
+var seed;
+var fs = require('fs');
+var path = require('path');
+var Promise;
+
+/**
+ * We receive the dbmigrate dependency from dbmigrate initially.
+ * This enables us to not have to rely on NODE_PATH.
+ */
+exports.setup = function (options, seedLink) {
+ dbm = options.dbmigrate;
+ type = dbm.dataType;
+ seed = seedLink;
+ Promise = options.Promise;
+};
+
+exports.up = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20230323132703-client-type-column-up.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports.down = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20230323132703-client-type-column-down.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports._meta = {
+ version: 1,
+};
diff --git a/sandbox/oauth-example/migrations/20210421113146-seed.js b/sandbox/oauth-example/migrations/20230524115047-login-activity.js
similarity index 55%
rename from sandbox/oauth-example/migrations/20210421113146-seed.js
rename to sandbox/oauth-example/migrations/20230524115047-login-activity.js
index 629a05737b..fc6fbcb7c3 100644
--- a/sandbox/oauth-example/migrations/20210421113146-seed.js
+++ b/sandbox/oauth-example/migrations/20230524115047-login-activity.js
@@ -7,14 +7,6 @@ var fs = require('fs');
var path = require('path');
var Promise;
-function handleFile(filePath, resolve, reject) {
- fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
- if (err) return reject(err);
- console.log('received data: ' + data);
-
- resolve(data);
- });
-}
/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
@@ -27,18 +19,36 @@ exports.setup = function (options, seedLink) {
};
exports.up = function (db) {
- var filePath = path.join(__dirname, 'sqls', '20210421113146-seed-up.sql');
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20230524115047-login-activity-up.sql',
+ );
return new Promise(function (resolve, reject) {
- handleFile(filePath, resolve, reject);
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
}).then(function (data) {
return db.runSql(data);
});
};
exports.down = function (db) {
- var filePath = path.join(__dirname, 'sqls', '20210421113146-seed-down.sql');
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20230524115047-login-activity-down.sql',
+ );
return new Promise(function (resolve, reject) {
- handleFile(filePath, resolve, reject);
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
}).then(function (data) {
return db.runSql(data);
});
diff --git a/sandbox/oauth-example/migrations/20240116123737-sync-with-user-tenant.js b/sandbox/oauth-example/migrations/20240116123737-sync-with-user-tenant.js
new file mode 100644
index 0000000000..5481f600c7
--- /dev/null
+++ b/sandbox/oauth-example/migrations/20240116123737-sync-with-user-tenant.js
@@ -0,0 +1,59 @@
+'use strict';
+
+var dbm;
+var type;
+var seed;
+var fs = require('fs');
+var path = require('path');
+var Promise;
+
+/**
+ * We receive the dbmigrate dependency from dbmigrate initially.
+ * This enables us to not have to rely on NODE_PATH.
+ */
+exports.setup = function (options, seedLink) {
+ dbm = options.dbmigrate;
+ type = dbm.dataType;
+ seed = seedLink;
+ Promise = options.Promise;
+};
+
+exports.up = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20240116123737-sync-with-user-tenant-up.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports.down = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20240116123737-sync-with-user-tenant-down.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports._meta = {
+ version: 1,
+};
diff --git a/sandbox/oauth-example/migrations/20241105074844-add-jwt-keys-schema.js b/sandbox/oauth-example/migrations/20241105074844-add-jwt-keys-schema.js
new file mode 100644
index 0000000000..b1ebc0e60c
--- /dev/null
+++ b/sandbox/oauth-example/migrations/20241105074844-add-jwt-keys-schema.js
@@ -0,0 +1,59 @@
+'use strict';
+
+var dbm;
+var type;
+var seed;
+var fs = require('fs');
+var path = require('path');
+var Promise;
+
+/**
+ * We receive the dbmigrate dependency from dbmigrate initially.
+ * This enables us to not have to rely on NODE_PATH.
+ */
+exports.setup = function (options, seedLink) {
+ dbm = options.dbmigrate;
+ type = dbm.dataType;
+ seed = seedLink;
+ Promise = options.Promise;
+};
+
+exports.up = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20241105074844-add-jwt-keys-schema-up.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports.down = function (db) {
+ var filePath = path.join(
+ __dirname,
+ 'sqls',
+ '20241105074844-add-jwt-keys-schema-down.sql',
+ );
+ return new Promise(function (resolve, reject) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function (err, data) {
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ }).then(function (data) {
+ return db.runSql(data);
+ });
+};
+
+exports._meta = {
+ version: 1,
+};
diff --git a/sandbox/oauth-example/migrations/database.json b/sandbox/oauth-example/migrations/database.json
index 414a359e8c..b50814c9ad 100644
--- a/sandbox/oauth-example/migrations/database.json
+++ b/sandbox/oauth-example/migrations/database.json
@@ -1,22 +1,22 @@
{
- "defaultEnv": "master",
- "master": {
- "driver": "pg",
- "host": {
- "ENV": "DB_HOST"
- },
- "port": {
- "ENV": "DB_PORT"
- },
- "user": {
- "ENV": "DB_USER"
- },
- "password": {
- "ENV": "DB_PASSWORD"
- },
- "database": {
- "ENV": "DB_DATABASE"
- }
+ "defaultEnv": "master",
+ "master": {
+ "driver": "pg",
+ "host": {
+ "ENV": "DB_HOST"
},
- "sql-file": true
+ "port": {
+ "ENV": "DB_PORT"
+ },
+ "user": {
+ "ENV": "DB_USER"
+ },
+ "password": {
+ "ENV": "DB_PASSWORD"
+ },
+ "database": {
+ "ENV": "DB_DATABASE"
+ }
+ },
+ "sql-file": true
}
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20210421113036-init-down.sql b/sandbox/oauth-example/migrations/sqls/20210318100600-init-down.sql
similarity index 100%
rename from sandbox/oauth-example/migrations/sqls/20210421113036-init-down.sql
rename to sandbox/oauth-example/migrations/sqls/20210318100600-init-down.sql
diff --git a/sandbox/oauth-example/migrations/sqls/20210421113036-init-up.sql b/sandbox/oauth-example/migrations/sqls/20210318100600-init-up.sql
similarity index 59%
rename from sandbox/oauth-example/migrations/sqls/20210421113036-init-up.sql
rename to sandbox/oauth-example/migrations/sqls/20210318100600-init-up.sql
index f860c3fc70..5d87000632 100644
--- a/sandbox/oauth-example/migrations/sqls/20210421113036-init-up.sql
+++ b/sandbox/oauth-example/migrations/sqls/20210318100600-init-up.sql
@@ -1,18 +1,17 @@
-DROP SCHEMA IF EXISTS main CASCADE;
-CREATE SCHEMA main;
+CREATE SCHEMA IF NOT EXISTS main;
SET search_path TO main,public;
GRANT ALL ON SCHEMA main TO public;
-CREATE TABLE main.auth_clients (
+CREATE TABLE IF NOT EXISTS main.auth_clients (
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY,
client_id varchar(50) NOT NULL ,
- client_secret varchar(50) NOT NULL ,
+ client_secret text NOT NULL ,
redirect_url varchar(200) ,
access_token_expiration integer DEFAULT 900 NOT NULL ,
refresh_token_expiration integer DEFAULT 86400 NOT NULL ,
auth_code_expiration integer DEFAULT 180 NOT NULL ,
- secret varchar(50) NOT NULL ,
+ secret text NOT NULL ,
created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
deleted bool DEFAULT false NOT NULL ,
@@ -21,22 +20,7 @@ CREATE TABLE main.auth_clients (
CONSTRAINT pk_auth_clients_id PRIMARY KEY ( id )
);
-CREATE TABLE main.groups (
- id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
- name varchar(200) NOT NULL ,
- description varchar(500) ,
- photo_url varchar(500) ,
- created_by uuid ,
- modified_by uuid ,
- created_on timestamptz DEFAULT CURRENT_TIMESTAMP ,
- modified_on timestamptz DEFAULT CURRENT_TIMESTAMP ,
- deleted bool DEFAULT false ,
- deleted_on timestamptz ,
- deleted_by uuid ,
- CONSTRAINT pk_groups_id PRIMARY KEY ( id )
- );
-
-CREATE TABLE main.roles (
+ CREATE TABLE IF NOT EXISTS main.roles (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
name varchar(100) NOT NULL ,
created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
@@ -50,8 +34,8 @@ CREATE TABLE main.roles (
deleted_on timestamptz ,
CONSTRAINT pk_roles_id PRIMARY KEY ( id )
);
-
-CREATE TABLE main.tenants (
+
+ CREATE TABLE IF NOT EXISTS main.tenants (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
name varchar(100) NOT NULL ,
status integer DEFAULT 0 NOT NULL ,
@@ -72,7 +56,25 @@ CREATE TABLE main.tenants (
CONSTRAINT idx_tenants UNIQUE ( "key" )
);
-CREATE TABLE main.users (
+ CREATE TABLE IF NOT EXISTS main.tenant_configs (
+ id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
+ config_key varchar(100) NOT NULL ,
+ config_value jsonb NOT NULL ,
+ created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
+ modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
+ created_by integer ,
+ modified_by integer ,
+ deleted bool DEFAULT false NOT NULL ,
+ tenant_id uuid NOT NULL ,
+ deleted_by uuid ,
+ deleted_on timestamptz ,
+ CONSTRAINT pk_tenant_configs_id PRIMARY KEY ( id ),
+ CONSTRAINT fk_tenant_configs_tenants FOREIGN KEY ( tenant_id ) REFERENCES main.tenants( id )
+
+ );
+
+
+CREATE TABLE IF NOT EXISTS main.users (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
first_name varchar(50) NOT NULL ,
middle_name varchar(50) ,
@@ -86,40 +88,16 @@ CREATE TABLE main.users (
modified_by uuid ,
deleted bool DEFAULT false NOT NULL ,
last_login timestamptz ,
- photo_url varchar(250) ,
auth_client_ids integer[] ,
gender char(1) ,
dob date ,
- designation varchar(50) ,
default_tenant_id uuid ,
deleted_by uuid ,
deleted_on timestamptz ,
CONSTRAINT pk_users_id PRIMARY KEY ( id )
);
-CREATE TABLE main.todo (
- id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
- title varchar(50) NOT NULL ,
- description varchar(150) NOT NULL ,
- items _text
- );
-
-CREATE TABLE main.tenant_configs (
- id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
- config_key varchar(100) NOT NULL ,
- config_value jsonb NOT NULL ,
- created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
- modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
- created_by integer ,
- modified_by integer ,
- deleted bool DEFAULT false NOT NULL ,
- tenant_id uuid NOT NULL ,
- deleted_by uuid ,
- deleted_on timestamptz ,
- CONSTRAINT pk_tenant_configs_id PRIMARY KEY ( id )
- );
-
-CREATE TABLE main.user_credentials (
+CREATE TABLE IF NOT EXISTS main.user_credentials (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
user_id uuid NOT NULL ,
auth_provider varchar(50) DEFAULT 'internal'::character varying NOT NULL ,
@@ -132,10 +110,12 @@ CREATE TABLE main.user_credentials (
deleted_on timestamptz ,
deleted_by uuid ,
CONSTRAINT pk_user_credentials_id PRIMARY KEY ( id ),
- CONSTRAINT idx_user_credentials_user_id UNIQUE ( user_id )
+ CONSTRAINT idx_user_credentials_user_id UNIQUE ( user_id ),
+ CONSTRAINT idx_user_credentials_uniq UNIQUE ( auth_provider, auth_id, auth_token, "password" ),
+ CONSTRAINT fk_user_credentials_users FOREIGN KEY ( user_id ) REFERENCES main.users( id )
);
-
-CREATE TABLE main.user_tenants (
+
+ CREATE TABLE IF NOT EXISTS main.user_tenants (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
user_id uuid NOT NULL ,
tenant_id uuid NOT NULL ,
@@ -147,38 +127,48 @@ CREATE TABLE main.user_tenants (
locale varchar(5) ,
deleted_by uuid ,
deleted_on timestamptz ,
- CONSTRAINT pk_user_tenants_id PRIMARY KEY ( id )
+ CONSTRAINT pk_user_tenants_id PRIMARY KEY ( id ),
+ CONSTRAINT fk_user_tenants_users FOREIGN KEY ( user_id ) REFERENCES main.users( id ) ,
+ CONSTRAINT fk_user_tenants_tenants FOREIGN KEY ( tenant_id ) REFERENCES main.tenants( id ) ,
+ CONSTRAINT fk_user_tenants_roles FOREIGN KEY ( role_id ) REFERENCES main.roles( id )
);
-CREATE TABLE main.user_groups (
+ CREATE TABLE IF NOT EXISTS main.user_permissions (
id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
user_tenant_id uuid NOT NULL ,
- group_id uuid NOT NULL ,
- created_on timestamptz DEFAULT CURRENT_TIMESTAMP ,
- modified_on timestamptz DEFAULT CURRENT_TIMESTAMP ,
- deleted bool DEFAULT false ,
+ permission text NOT NULL ,
+ allowed bool NOT NULL ,
+ created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
+ modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
created_by uuid ,
modified_by uuid ,
+ deleted bool DEFAULT false NOT NULL ,
deleted_on timestamptz ,
deleted_by uuid ,
- CONSTRAINT pk_user_groups_id PRIMARY KEY ( id )
+ CONSTRAINT pk_user_permissions_id PRIMARY KEY ( id ),
+ CONSTRAINT fk_user_permissions FOREIGN KEY ( user_tenant_id ) REFERENCES main.user_tenants( id )
+
);
-CREATE TABLE main.user_permissions (
- id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
- user_tenant_id uuid NOT NULL ,
- permission varchar(50) NOT NULL ,
- allowed bool NOT NULL ,
+CREATE TABLE IF NOT EXISTS main.user_resources (
+ deleted bool DEFAULT false NOT NULL ,
+ deleted_on timestamptz ,
+ deleted_by uuid ,
created_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
modified_on timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL ,
created_by uuid ,
modified_by uuid ,
- deleted bool DEFAULT false NOT NULL ,
- deleted_on timestamptz ,
- deleted_by uuid ,
- CONSTRAINT pk_user_permissions_id PRIMARY KEY ( id )
+ id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
+ user_tenant_id uuid ,
+ resource_name varchar(50) ,
+ resource_value varchar(100) ,
+ allowed bool DEFAULT true NOT NULL ,
+ CONSTRAINT user_resources_pkey PRIMARY KEY ( id ),
+ CONSTRAINT fk_user_resources FOREIGN KEY ( user_tenant_id ) REFERENCES main.user_tenants( id )
+
);
+
CREATE OR REPLACE FUNCTION main.moddatetime()
RETURNS trigger
LANGUAGE plpgsql
@@ -190,35 +180,18 @@ END;
$function$
;
-CREATE TRIGGER mdt_auth_clients BEFORE UPDATE ON main.auth_clients FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_roles BEFORE UPDATE ON main.roles FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_tenant_configs BEFORE UPDATE ON main.tenant_configs FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_tenants BEFORE UPDATE ON main.tenants FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_user_credentials BEFORE UPDATE ON main.user_credentials FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_user_permissions BEFORE UPDATE ON main.user_permissions FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_user_tenants BEFORE UPDATE ON main.user_tenants FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-CREATE TRIGGER mdt_users BEFORE UPDATE ON main.users FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-
-ALTER TABLE main.tenant_configs ADD CONSTRAINT fk_tenant_configs_tenants FOREIGN KEY ( tenant_id ) REFERENCES main.tenants( id );
-
-ALTER TABLE main.user_credentials ADD CONSTRAINT fk_user_credentials_users FOREIGN KEY ( user_id ) REFERENCES main.users( id );
+CREATE OR REPLACE TRIGGER mdt_auth_clients BEFORE UPDATE ON main.auth_clients FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_groups ADD CONSTRAINT fk_user_tenant FOREIGN KEY ( user_tenant_id ) REFERENCES main.user_tenants( id );
+CREATE OR REPLACE TRIGGER mdt_roles BEFORE UPDATE ON main.roles FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_groups ADD CONSTRAINT fk_groups FOREIGN KEY ( group_id ) REFERENCES main.groups( id );
+CREATE OR REPLACE TRIGGER mdt_tenant_configs BEFORE UPDATE ON main.tenant_configs FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_permissions ADD CONSTRAINT fk_user_permissions FOREIGN KEY ( user_tenant_id ) REFERENCES main.user_tenants( id );
+CREATE OR REPLACE TRIGGER mdt_tenants BEFORE UPDATE ON main.tenants FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_tenants ADD CONSTRAINT fk_user_tenants_users FOREIGN KEY ( user_id ) REFERENCES main.users( id );
+CREATE OR REPLACE TRIGGER mdt_user_credentials BEFORE UPDATE ON main.user_credentials FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_tenants ADD CONSTRAINT fk_user_tenants_tenants FOREIGN KEY ( tenant_id ) REFERENCES main.tenants( id );
+CREATE OR REPLACE TRIGGER mdt_user_permissions BEFORE UPDATE ON main.user_permissions FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
-ALTER TABLE main.user_tenants ADD CONSTRAINT fk_user_tenants_roles FOREIGN KEY ( role_id ) REFERENCES main.roles( id );
+CREATE OR REPLACE TRIGGER mdt_user_tenants BEFORE UPDATE ON main.user_tenants FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
+CREATE OR REPLACE TRIGGER mdt_users BEFORE UPDATE ON main.users FOR EACH ROW EXECUTE PROCEDURE main.moddatetime('modified_on');
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20210421113146-seed-down.sql b/sandbox/oauth-example/migrations/sqls/20210421113146-seed-down.sql
deleted file mode 100644
index 0e68c90bbe..0000000000
--- a/sandbox/oauth-example/migrations/sqls/20210421113146-seed-down.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-SET search_path TO main,public;
-
-DELETE FROM user_credentials;
-DELETE FROM user_tenants;
-DELETE FROM users;
-DELETE FROM tenants;
-DELETE FROM roles;
-DELETE FROM auth_clients;
diff --git a/sandbox/oauth-example/migrations/sqls/20210421113146-seed-up.sql b/sandbox/oauth-example/migrations/sqls/20210421113146-seed-up.sql
deleted file mode 100644
index b4113d3e8b..0000000000
--- a/sandbox/oauth-example/migrations/sqls/20210421113146-seed-up.sql
+++ /dev/null
@@ -1,51 +0,0 @@
-SET search_path
-TO main,public;
-
-/* Inserting auth clients */
-insert into auth_clients
- (client_id, client_secret, secret)
-values
- ('test_client_id', 'test_client_secret', 'secret');
-
--- Inserting roles
-insert into roles
- (name, permissions, role_type)
-values
- ('Admin', '{CreateTodo,UpdateTodo,DeleteTodo}', 0);
-
-insert into roles
- (name, permissions, role_type)
-values
- ('Others', '{}', 1);
-
--- Inserting tenants
-insert into tenants
- (name, status, key)
-values
- ('Master', 1, 'master');
-
--- Inserting Admin User
-insert into users
- (first_name, last_name, username, email, default_tenant_id)
-select 'Admin', 'User', 'admin@example.com', 'admin@example.com', id
-from tenants
-where key = 'master';
-
-insert into user_tenants
- (user_id, tenant_id, status, role_id)
-select (select id
- from users
- where username = 'admin@example.com'), (select id
- from tenants
- where key = 'master'), 1, id
-from roles
-where role_type = 0;
-
-insert into user_credentials
- (user_id, auth_provider, password)
-select id, 'internal', '$2a$10$TOLMGK43MjbibS8Jap2RXeHl3.4sJcR3eFbms2dBll2LTMggSK9hG'
-from users
-where username = 'admin@example.com';
-update users set auth_client_ids = ARRAY[(select id from auth_clients where client_id = 'test_client_id')::integer];
-
-
diff --git a/sandbox/oauth-example/migrations/sqls/20220607063927-secret-key-column-up.sql b/sandbox/oauth-example/migrations/sqls/20220607063927-secret-key-column-up.sql
index d66c203490..570a7ab069 100644
--- a/sandbox/oauth-example/migrations/sqls/20220607063927-secret-key-column-up.sql
+++ b/sandbox/oauth-example/migrations/sqls/20220607063927-secret-key-column-up.sql
@@ -1,2 +1,2 @@
ALTER TABLE main.user_credentials
-ADD secret_key varchar(100);
+ADD IF NOT EXISTS secret_key text;
diff --git a/sandbox/oauth-example/migrations/sqls/20221123082900-updated-init-down.sql b/sandbox/oauth-example/migrations/sqls/20221110095658-updated-init-down.sql
similarity index 100%
rename from sandbox/oauth-example/migrations/sqls/20221123082900-updated-init-down.sql
rename to sandbox/oauth-example/migrations/sqls/20221110095658-updated-init-down.sql
diff --git a/sandbox/oauth-example/migrations/sqls/20221110095658-updated-init-up.sql b/sandbox/oauth-example/migrations/sqls/20221110095658-updated-init-up.sql
new file mode 100644
index 0000000000..22c5208465
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20221110095658-updated-init-up.sql
@@ -0,0 +1,11 @@
+ALTER TABLE main.auth_clients
+ADD IF NOT EXISTS created_by varchar(100),
+ADD IF NOT EXISTS modified_by varchar(100);
+
+ALTER TABLE main.user_credentials
+ADD IF NOT EXISTS created_by varchar(100),
+ADD IF NOT EXISTS modified_by varchar(100);
+
+ALTER TABLE main.user_tenants
+ADD IF NOT EXISTS created_by varchar(100),
+ADD IF NOT EXISTS modified_by varchar(100);
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20221123082900-updated-init-up.sql b/sandbox/oauth-example/migrations/sqls/20221123082900-updated-init-up.sql
deleted file mode 100644
index 7a3da56364..0000000000
--- a/sandbox/oauth-example/migrations/sqls/20221123082900-updated-init-up.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-ALTER TABLE main.auth_clients
-ADD created_by varchar(100),
-ADD modified_by varchar(100);
-
-ALTER TABLE main.user_credentials
-ADD created_by varchar(100),
-ADD modified_by varchar(100);
-
-ALTER TABLE main.user_tenants
-ADD created_by varchar(100),
-ADD modified_by varchar(100);
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-down.sql b/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-down.sql
new file mode 100644
index 0000000000..752870fd2f
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-down.sql
@@ -0,0 +1,3 @@
+/* Replace with your SQL commands */
+
+ALTER TABLE main.auth_clients DROP COLUMN client_type;
diff --git a/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-up.sql b/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-up.sql
new file mode 100644
index 0000000000..c9c45ba9b1
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20230323132703-client-type-column-up.sql
@@ -0,0 +1,4 @@
+/* Replace with your SQL commands */
+
+ALTER TABLE main.auth_clients
+ADD IF NOT EXISTS client_type varchar(100) DEFAULT 'public';
diff --git a/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-down.sql b/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-down.sql
new file mode 100644
index 0000000000..fa7e8d10a1
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-down.sql
@@ -0,0 +1,6 @@
+/* Replace with your SQL commands */
+
+SET search_path TO main,public;
+GRANT ALL ON SCHEMA main TO public;
+
+drop table main.login_activity;
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-up.sql b/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-up.sql
new file mode 100644
index 0000000000..075c744eac
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20230524115047-login-activity-up.sql
@@ -0,0 +1,16 @@
+/* Replace with your SQL commands */
+
+SET search_path TO main,public;
+GRANT ALL ON SCHEMA main TO public;
+
+CREATE TABLE main.login_activity (
+ id uuid DEFAULT md5(random()::text || clock_timestamp()::text)::uuid NOT NULL ,
+ actor text NOT NULL,
+ tenant_id text,
+ login_time timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ token_payload text NOT NULL,
+ login_type text NOT NULL,
+ device_info text,
+ ip_address text,
+ CONSTRAINT pk_login_activity PRIMARY KEY ( id )
+);
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-down.sql b/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-down.sql
new file mode 100644
index 0000000000..44f074ea89
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-down.sql
@@ -0,0 +1 @@
+/* Replace with your SQL commands */
\ No newline at end of file
diff --git a/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-up.sql b/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-up.sql
new file mode 100644
index 0000000000..98849b18b4
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20240116123737-sync-with-user-tenant-up.sql
@@ -0,0 +1,15 @@
+/* Replace with your SQL commands */
+
+ALTER TABLE main.roles
+ADD IF NOT EXISTS tenant_id uuid NOT NULL,
+ADD IF NOT EXISTS allowed_clients text[],
+ADD IF NOT EXISTS description varchar(500);
+
+ALTER TABLE main.tenants
+ADD IF NOT EXISTS website varchar(100);
+
+ALTER TABLE main.users
+ADD IF NOT EXISTS photo_url text,
+ADD IF NOT EXISTS designation varchar(50);
+
+
diff --git a/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-down.sql b/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-down.sql
new file mode 100644
index 0000000000..fbcccb9d0c
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-down.sql
@@ -0,0 +1 @@
+DROP TABLE main.jwt_keys;
diff --git a/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-up.sql b/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-up.sql
new file mode 100644
index 0000000000..f644e574f5
--- /dev/null
+++ b/sandbox/oauth-example/migrations/sqls/20241105074844-add-jwt-keys-schema-up.sql
@@ -0,0 +1,7 @@
+CREATE TABLE main.jwt_keys (
+ id SERIAL PRIMARY KEY,
+ key_id VARCHAR(100) UNIQUE NOT NULL,
+ public_key TEXT NOT NULL, -- Public key in PEM format
+ private_key TEXT NOT NULL, -- Private key in PEM format
+ created_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
diff --git a/sandbox/oauth-example/package.json b/sandbox/oauth-example/package.json
index df15b94e0e..babe5094d8 100644
--- a/sandbox/oauth-example/package.json
+++ b/sandbox/oauth-example/package.json
@@ -1,16 +1,16 @@
{
- "name": "@sourceloop/oauth-example-api",
- "version": "0.5.13",
- "description": "oauth example.",
+ "name": "o-auth",
+ "version": "0.0.1",
+ "description": "auth",
"keywords": [
- "loopback-application",
+ "loopback-microservice",
"loopback"
],
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"engines": {
- "node": "18 || 20"
+ "node": ">=18"
},
"scripts": {
"build": "lb-tsc",
@@ -23,28 +23,34 @@
"eslint": "eslint --report-unused-disable-directives .",
"eslint:fix": "npm run eslint -- --fix",
"pretest": "npm run rebuild",
- "test": "echo 'No Tests'",
- "posttest": "npm run lint",
- "test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js && npm run posttest",
- "docker:build": "docker build -t auth-service .",
- "docker:run": "docker run -p 3000:3000 -d auth-service",
+ "test": "lb-mocha --allow-console-logs \"dist/__tests__\"",
+ "test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js",
+ "docker:build": "DOCKER_BUILDKIT=1 sudo docker build --build-arg NR_ENABLED=$NR_ENABLED_VALUE --build-arg FROM_FOLDER=services --build-arg SERVICE_NAME=authentication-service -t $IMAGE_REPO_NAME/$npm_package_name:$npm_package_version ../../. -f ./Dockerfile",
+ "docker:run": "docker run -p 3000:3000 -d auth",
+ "symlink-resolver": "symlink-resolver",
+ "resolve-links": "npm run symlink-resolver build ./node_modules/@local",
"premigrate": "npm run build",
"migrate": "node ./dist/migrate",
"preopenapi-spec": "npm run build",
"openapi-spec": "node ./dist/openapi-spec",
- "prestart": "npm run rebuild",
- "start": "node -r source-map-support/register .",
+ "prestart": "npm run clean && npm run openapi-spec",
+ "start": "node -r ./dist/opentelemetry-registry.js -r source-map-support/register .",
+ "dev": "nodemon --watch src -e ts --exec \"npm run start\"",
"clean": "lb-clean dist *.tsbuildinfo .eslintcache",
"rebuild": "npm run clean && npm run build",
- "db:migrate": "./node_modules/db-migrate/bin/db-migrate up --config './migrations/database.json'",
- "db:migrate:down": "./node_modules/db-migrate/bin/db-migrate down --config './migrations/database.json'",
- "db:migrate:reset": "./node_modules/db-migrate/bin/db-migrate reset --config './migrations/database.json'"
+ "docker:push": " docker push $IMAGE_REPO_NAME/$npm_package_name:$npm_package_version",
+ "docker:build:dev": "DOCKER_BUILDKIT=1 sudo docker build --build-arg NR_ENABLED=$NR_ENABLED_VALUE --build-arg FROM_FOLDER=services --build-arg SERVICE_NAME=authentication-service -t $IMAGE_REPO_NAME/$npm_package_name:$npm_package_version ../../. -f ./Dockerfile",
+ "docker:push:dev": " docker push $IMAGE_REPO_NAME/$npm_package_name:$npm_package_version",
+ "coverage": "nyc npm run test",
+ "db:migrate": "../../node_modules/db-migrate/bin/db-migrate up --config './migrations/database.json'",
+ "db:migrate:down": "../../node_modules/db-migrate/bin/db-migrate down --config './migrations/database.json'",
+ "db:migrate:reset": "../../node_modules/db-migrate/bin/db-migrate reset --config './migrations/database.json'"
},
"repository": {
"type": "git",
"url": ""
},
- "author": "Ankur ",
+ "author": "Tyagi-Sunny",
"license": "MIT",
"files": [
"README.md",
@@ -59,23 +65,40 @@
"@loopback/rest": "^14.0.9",
"@loopback/rest-explorer": "^7.0.9",
"@loopback/service-proxy": "^7.0.9",
- "@sourceloop/authentication-service": "^20.0.2",
- "bcrypt": "^5.0.1",
+ "@loopback/openapi-v3": "^10.0.9",
+ "@loopback/context": "^7.0.9",
+ "@sourceloop/core": "^15.0.2",
+ "loopback4-authentication": "^12.1.1",
+ "loopback4-authorization": "^7.0.3",
+ "swagger-stats": "^0.99.5",
+ "@opentelemetry/exporter-jaeger": "^1.15.0",
+ "@opentelemetry/sdk-trace-node": "^1.15.0",
+ "@opentelemetry/plugin-dns": "^0.15.0",
+ "@opentelemetry/plugin-http": "^0.18.2",
+ "@opentelemetry/plugin-https": "^0.18.2",
+ "@opentelemetry/plugin-pg": "^0.15.0",
+ "@opentelemetry/plugin-pg-pool": "^0.15.0",
+ "@opentelemetry/sdk-trace-base": "^1.15.0",
"db-migrate": "^1.0.0-beta.21",
"db-migrate-pg": "^1.3.0",
+ "symlink-resolver": "0.2.1",
"dotenv": "^16.4.5",
"dotenv-extended": "^2.9.0",
"loopback-connector-postgresql": "^7.1.8",
- "tslib": "^2.6.2"
+ "loopback-connector-kv-redis": "^4.0.0",
+ "tslib": "^2.6.2",
+ "@sourceloop/authentication-service": "^20.0.2"
},
"devDependencies": {
"@loopback/build": "^11.0.8",
- "@loopback/eslint-config": "^15.0.4",
+ "source-map-support": "^0.5.21",
+ "nodemon": "^2.0.21",
+ "nyc": "^15.1.0",
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
"@loopback/testlab": "^7.0.8",
- "@types/bcrypt": "^5.0.0",
"@types/node": "^20.12.7",
+ "@loopback/eslint-config": "^15.0.4",
"eslint": "^8.57.0",
- "source-map-support": "^0.5.21",
"typescript": "^5.4.5"
}
-}
+}
\ No newline at end of file
diff --git a/sandbox/oauth-example/public/index.html b/sandbox/oauth-example/public/index.html
index 3e9f36f599..6ddfab83e2 100644
--- a/sandbox/oauth-example/public/index.html
+++ b/sandbox/oauth-example/public/index.html
@@ -1,7 +1,7 @@
- oauth example
+ auth
@@ -80,18 +80,22 @@
-
auth-service
+
auth
Version 1.0.0
-
-
+
+
+
diff --git a/sandbox/oauth-example/src/__tests__/acceptance/home-page.acceptance.ts b/sandbox/oauth-example/src/__tests__/acceptance/home-page.acceptance.ts
index 1ffdf417f0..e56145a78c 100644
--- a/sandbox/oauth-example/src/__tests__/acceptance/home-page.acceptance.ts
+++ b/sandbox/oauth-example/src/__tests__/acceptance/home-page.acceptance.ts
@@ -1,13 +1,9 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {Client} from '@loopback/testlab';
-import {AuthServiceApplication} from '../..';
+import {AuthApplication} from '../..';
import {setupApplication} from './test-helper';
describe('HomePage', () => {
- let app: AuthServiceApplication;
+ let app: AuthApplication;
let client: Client;
before('setupApplication', async () => {
diff --git a/sandbox/oauth-example/src/__tests__/acceptance/ping.controller.acceptance.ts b/sandbox/oauth-example/src/__tests__/acceptance/ping.controller.acceptance.ts
index 9f31316af9..5353fb9b88 100644
--- a/sandbox/oauth-example/src/__tests__/acceptance/ping.controller.acceptance.ts
+++ b/sandbox/oauth-example/src/__tests__/acceptance/ping.controller.acceptance.ts
@@ -1,13 +1,9 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {Client, expect} from '@loopback/testlab';
-import {AuthServiceApplication} from '../..';
+import {AuthApplication} from '../..';
import {setupApplication} from './test-helper';
describe('PingController', () => {
- let app: AuthServiceApplication;
+ let app: AuthApplication;
let client: Client;
before('setupApplication', async () => {
diff --git a/sandbox/oauth-example/src/__tests__/acceptance/test-helper.ts b/sandbox/oauth-example/src/__tests__/acceptance/test-helper.ts
index be0b911a79..5583ab5b3a 100644
--- a/sandbox/oauth-example/src/__tests__/acceptance/test-helper.ts
+++ b/sandbox/oauth-example/src/__tests__/acceptance/test-helper.ts
@@ -1,13 +1,9 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
+import {AuthApplication} from '../..';
import {
- Client,
createRestAppClient,
givenHttpServerConfig,
+ Client,
} from '@loopback/testlab';
-import {AuthServiceApplication} from '../..';
export async function setupApplication(): Promise {
const restConfig = givenHttpServerConfig({
@@ -17,11 +13,22 @@ export async function setupApplication(): Promise {
// host: process.env.HOST,
// port: +process.env.PORT,
});
+ setUpEnv();
- const app = new AuthServiceApplication({
+ const app = new AuthApplication({
rest: restConfig,
});
+ app.bind('datasources.config.db').to({
+ name: 'db',
+ connector: 'memory',
+ });
+
+ app.bind(`datasources.config.${process.env.REDIS_NAME}`).to({
+ name: process.env.REDIS_NAME,
+ connector: 'kv-memory',
+ });
+
await app.boot();
await app.start();
@@ -30,7 +37,15 @@ export async function setupApplication(): Promise {
return {app, client};
}
+function setUpEnv() {
+ process.env.NODE_ENV = 'test';
+ process.env.ENABLE_TRACING = '0';
+ process.env.ENABLE_OBF = '0';
+ process.env.REDIS_NAME = 'redis';
+ process.env.HOST = 'localhost';
+}
+
export interface AppWithClient {
- app: AuthServiceApplication;
+ app: AuthApplication;
client: Client;
}
diff --git a/sandbox/oauth-example/src/application.ts b/sandbox/oauth-example/src/application.ts
index 7b716c523e..9dda77f8f4 100644
--- a/sandbox/oauth-example/src/application.ts
+++ b/sandbox/oauth-example/src/application.ts
@@ -1,82 +1,116 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {BootMixin} from '@loopback/boot';
import {ApplicationConfig} from '@loopback/core';
-import {RepositoryMixin} from '@loopback/repository';
-import {RestApplication} from '@loopback/rest';
import {
RestExplorerBindings,
RestExplorerComponent,
} from '@loopback/rest-explorer';
-import {ServiceMixin} from '@loopback/service-proxy';
+import * as dotenv from 'dotenv';
+import * as dotenvExt from 'dotenv-extended';
+import {AuthenticationComponent, Strategies} from 'loopback4-authentication';
+import {
+ AuthorizationBindings,
+ AuthorizationComponent,
+} from 'loopback4-authorization';
+import {
+ ServiceSequence,
+ SFCoreBindings,
+ BearerVerifierBindings,
+ BearerVerifierComponent,
+ BearerVerifierConfig,
+ BearerVerifierType,
+ SECURITY_SCHEME_SPEC,
+} from '@sourceloop/core';
import {
AuthenticationServiceComponent,
+ AuthServiceBindings,
SignUpBindings,
} from '@sourceloop/authentication-service';
-import {Strategies} from 'loopback4-authentication';
-import {SamlStrategyFactoryProvider} from 'loopback4-authentication/SAML';
-import {GoogleAuthStrategyFactoryProvider} from 'loopback4-authentication/passport-google-oauth2';
-import {LocalPasswordStrategyFactoryProvider} from 'loopback4-authentication/passport-local';
+import {RepositoryMixin} from '@loopback/repository';
+import {RestApplication} from '@loopback/rest';
+import {ServiceMixin} from '@loopback/service-proxy';
import path from 'path';
-import {
- AzureAdSignupProvider,
- FacebookOauth2SignupProvider,
- GoogleOauth2SignupProvider,
- SamlVerifyProvider,
-} from './providers';
-import {SamlSignupProvider} from './providers/saml-signup.provider';
-import {MySequence} from './sequence';
+import * as openapi from './openapi.json';
+import {GoogleOauth2SignupProvider} from './providers';
+import {GoogleAuthStrategyFactoryProvider} from 'loopback4-authentication/passport-google-oauth2';
export {ApplicationConfig};
-export class AuthServiceApplication extends BootMixin(
+export class AuthApplication extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options: ApplicationConfig = {}) {
+ const port = 3000;
+ dotenv.config();
+ dotenvExt.load({
+ schema: '.env.example',
+ errorOnMissing: process.env.NODE_ENV !== 'test',
+ includeProcessEnv: true,
+ });
+ options.rest = options.rest ?? {};
+ options.rest.basePath = process.env.BASE_PATH ?? '';
+ options.rest.port = +(process.env.PORT ?? port);
+ options.rest.host = process.env.HOST;
+ options.rest.openApiSpec = {
+ endpointMapping: {
+ [`${options.rest.basePath}/openapi.json`]: {
+ version: '3.0.0',
+ format: 'json',
+ },
+ },
+ };
+
super(options);
- // Set up the custom sequence
- this.sequence(MySequence);
+ // To check if monitoring is enabled from env or not
+ const enableObf = !!+(process.env.ENABLE_OBF ?? 0);
+ // To check if authorization is enabled for swagger stats or not
+ const authentication =
+ process.env.SWAGGER_USER && process.env.SWAGGER_PASSWORD ? true : false;
+ const obj = {
+ enableObf,
+ obfPath: process.env.OBF_PATH ?? '/obf',
+ openapiSpec: openapi,
+ authentication: authentication,
+ swaggerUsername: process.env.SWAGGER_USER,
+ swaggerPassword: process.env.SWAGGER_PASSWORD,
+ };
+ this.bind(SFCoreBindings.config).to(obj);
- // Set up default home page
- this.static('/', path.join(__dirname, '../public'));
+ // Set up the custom sequence
+ this.sequence(ServiceSequence);
- // Customize @loopback/rest-explorer configuration here
- this.configure(RestExplorerBindings.COMPONENT).to({
- path: '/explorer',
+ // Add authentication component
+ this.component(AuthenticationComponent);
+ this.bind(AuthServiceBindings.Config).to({
+ useSymmetricEncryption: true,
});
- this.component(RestExplorerComponent);
-
this.component(AuthenticationServiceComponent);
-
- this.bind(Strategies.Passport.LOCAL_STRATEGY_FACTORY.key).toProvider(
- LocalPasswordStrategyFactoryProvider,
- );
-
this.bind(SignUpBindings.GOOGLE_SIGN_UP_PROVIDER).toProvider(
GoogleOauth2SignupProvider,
);
- this.bind(
- Strategies.Passport.GOOGLE_OAUTH2_STRATEGY_FACTORY.key,
- ).toProvider(GoogleAuthStrategyFactoryProvider);
- this.bind(SignUpBindings.FACEBOOK_SIGN_UP_PROVIDER).toProvider(
- FacebookOauth2SignupProvider,
- );
- this.bind(SignUpBindings.AZURE_AD_SIGN_UP_PROVIDER).toProvider(
- AzureAdSignupProvider,
+ this.bind(Strategies.Passport.GOOGLE_OAUTH2_STRATEGY_FACTORY).toProvider(
+ GoogleAuthStrategyFactoryProvider,
);
+ // Add bearer verifier component
+ this.bind(BearerVerifierBindings.Config).to({
+ type: BearerVerifierType.service,
+ } as BearerVerifierConfig);
+ this.component(BearerVerifierComponent);
+ // Add authorization component
+ this.bind(AuthorizationBindings.CONFIG).to({
+ allowAlwaysPaths: ['/explorer', '/openapi.json'],
+ });
+ this.component(AuthorizationComponent);
- this.bind(SignUpBindings.SAML_SIGN_UP_PROVIDER).toProvider(
- SamlSignupProvider,
- );
+ // Set up default home page
+ this.static('/', path.join(__dirname, '../public'));
- this.bind(Strategies.Passport.SAML_VERIFIER).toProvider(SamlVerifyProvider);
+ // Customize @loopback/rest-explorer configuration here
+ this.configure(RestExplorerBindings.COMPONENT).to({
+ path: '/explorer',
+ });
- this.bind(Strategies.Passport.SAML_STRATEGY_FACTORY.key).toProvider(
- SamlStrategyFactoryProvider,
- );
+ this.component(RestExplorerComponent);
this.projectRoot = __dirname;
// Customize @loopback/boot Booter Conventions here
@@ -88,5 +122,18 @@ export class AuthServiceApplication extends BootMixin(
nested: true,
},
};
+
+ this.api({
+ openapi: '3.0.0',
+ info: {
+ title: 'auth',
+ version: '1.0.0',
+ },
+ paths: {},
+ components: {
+ securitySchemes: SECURITY_SCHEME_SPEC,
+ },
+ servers: [{url: '/'}],
+ });
}
}
diff --git a/sandbox/oauth-example/src/controllers/home-page.controller.ts b/sandbox/oauth-example/src/controllers/home-page.controller.ts
new file mode 100644
index 0000000000..4e6f52513c
--- /dev/null
+++ b/sandbox/oauth-example/src/controllers/home-page.controller.ts
@@ -0,0 +1,39 @@
+import {get} from '@loopback/openapi-v3';
+import * as fs from 'fs';
+import * as path from 'path';
+import {inject} from '@loopback/context';
+import {RestBindings, Response} from '@loopback/rest';
+import {authorize} from 'loopback4-authorization';
+import {STATUS_CODE} from '@sourceloop/core';
+
+export class HomePageController {
+ private readonly html: string;
+ constructor(
+ @inject(RestBindings.Http.RESPONSE)
+ private readonly response: Response,
+ ) {
+ this.html = fs.readFileSync(
+ path.join(__dirname, '../../public/index.html'),
+ 'utf-8',
+ );
+ // Replace base path placeholder from env
+ this.html = this.html.replace(
+ /\$\{basePath\}/g,
+ process.env.BASE_PATH ?? '',
+ );
+ }
+
+ @authorize({permissions: ['*']})
+ @get('/', {
+ responses: {
+ [STATUS_CODE.OK]: {
+ description: 'Home Page',
+ content: {'text/html': {schema: {type: 'string'}}},
+ },
+ },
+ })
+ homePage() {
+ this.response.status(STATUS_CODE.OK).contentType('html').send(this.html);
+ return this.response;
+ }
+}
diff --git a/sandbox/oauth-example/src/controllers/index.ts b/sandbox/oauth-example/src/controllers/index.ts
index 76abc8e2f1..d20736dff8 100644
--- a/sandbox/oauth-example/src/controllers/index.ts
+++ b/sandbox/oauth-example/src/controllers/index.ts
@@ -1,5 +1,2 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
export * from './ping.controller';
+export * from './home-page.controller';
diff --git a/sandbox/oauth-example/src/controllers/ping.controller.ts b/sandbox/oauth-example/src/controllers/ping.controller.ts
index 65cf734a32..56b0d46398 100644
--- a/sandbox/oauth-example/src/controllers/ping.controller.ts
+++ b/sandbox/oauth-example/src/controllers/ping.controller.ts
@@ -1,20 +1,11 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {inject} from '@loopback/core';
-import {
- get,
- Request,
- response,
- ResponseObject,
- RestBindings,
-} from '@loopback/rest';
+import {Request, RestBindings, get, ResponseObject} from '@loopback/rest';
+import {authorize} from 'loopback4-authorization';
+import {STATUS_CODE} from '@sourceloop/core';
/**
* OpenAPI response for ping()
*/
-const statusCode = 200;
const PING_RESPONSE: ResponseObject = {
description: 'Ping Response',
content: {
@@ -48,8 +39,12 @@ export class PingController {
) {}
// Map to `GET /ping`
- @get('/ping')
- @response(statusCode, PING_RESPONSE)
+ @authorize({permissions: ['*']})
+ @get('/ping', {
+ responses: {
+ [STATUS_CODE.OK]: PING_RESPONSE,
+ },
+ })
ping(): object {
// Reply with a greeting, the current time, the url, and request headers
return {
diff --git a/sandbox/oauth-example/src/datasources/db.datasource.ts b/sandbox/oauth-example/src/datasources/auth.datasource.ts
similarity index 54%
rename from sandbox/oauth-example/src/datasources/db.datasource.ts
rename to sandbox/oauth-example/src/datasources/auth.datasource.ts
index b92709075d..3df40c0002 100644
--- a/sandbox/oauth-example/src/datasources/db.datasource.ts
+++ b/sandbox/oauth-example/src/datasources/auth.datasource.ts
@@ -1,20 +1,20 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
import {juggler} from '@loopback/repository';
import {AuthDbSourceName} from '@sourceloop/authentication-service';
+const DEFAULT_MAX_CONNECTIONS = 25;
+const DEFAULT_DB_IDLE_TIMEOUT_MILLIS = 60000;
+const DEFAULT_DB_CONNECTION_TIMEOUT_MILLIS = 2000;
+
const config = {
- name: AuthDbSourceName,
+ name: 'auth',
connector: 'postgresql',
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
+ schema: process.env.DB_SCHEMA,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
- schema: process.env.DB_SCHEMA,
};
// Observe application's life cycle to disconnect the datasource when
@@ -22,17 +22,33 @@ const config = {
// gracefully. The `stop()` method is inherited from `juggler.DataSource`.
// Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html
@lifeCycleObserver('datasource')
-export class DbDataSource
+export class AuthDataSource
extends juggler.DataSource
implements LifeCycleObserver
{
- static readonly dataSourceName = AuthDbSourceName;
+ static dataSourceName = AuthDbSourceName;
+
static readonly defaultConfig = config;
constructor(
- @inject('datasources.config.db', {optional: true})
+ @inject('datasources.config.auth', {optional: true})
dsConfig: object = config,
) {
+ if (!!+(process.env.ENABLE_DB_CONNECTION_POOLING ?? 0)) {
+ const dbPool = {
+ max: +(process.env.DB_MAX_CONNECTIONS ?? DEFAULT_MAX_CONNECTIONS),
+ idleTimeoutMillis: +(
+ process.env.DB_IDLE_TIMEOUT_MILLIS ?? DEFAULT_DB_IDLE_TIMEOUT_MILLIS
+ ),
+ connectionTimeoutMillis: +(
+ process.env.DB_CONNECTION_TIMEOUT_MILLIS ??
+ DEFAULT_DB_CONNECTION_TIMEOUT_MILLIS
+ ),
+ };
+
+ dsConfig = {...dsConfig, ...dbPool};
+ }
+
super(dsConfig);
}
}
diff --git a/sandbox/oauth-example/src/datasources/index.ts b/sandbox/oauth-example/src/datasources/index.ts
index 0a6f13b851..d3aaddf849 100644
--- a/sandbox/oauth-example/src/datasources/index.ts
+++ b/sandbox/oauth-example/src/datasources/index.ts
@@ -1,6 +1,2 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-export * from './db.datasource';
+export * from './auth.datasource';
export * from './redis.datasource';
diff --git a/sandbox/oauth-example/src/datasources/redis.datasource.ts b/sandbox/oauth-example/src/datasources/redis.datasource.ts
index 9c05cc16c1..de47ed34ff 100644
--- a/sandbox/oauth-example/src/datasources/redis.datasource.ts
+++ b/sandbox/oauth-example/src/datasources/redis.datasource.ts
@@ -1,19 +1,35 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
-import {juggler} from '@loopback/repository';
+import {AnyObject, juggler} from '@loopback/repository';
+import {readFileSync} from 'fs';
import {AuthCacheSourceName} from '@sourceloop/authentication-service';
const config = {
- name: AuthCacheSourceName,
+ name: process.env.REDIS_NAME,
connector: 'kv-redis',
- url: '',
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
- database: process.env.REDIS_DATABASE,
+ db: process.env.REDIS_DATABASE,
+ url: process.env.REDIS_URL,
+ tls:
+ +process.env.REDIS_TLS_ENABLED! ||
+ (process.env.REDIS_TLS_CERT
+ ? {
+ ca: readFileSync(process.env.REDIS_TLS_CERT),
+ }
+ : undefined),
+ sentinels:
+ +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINELS
+ ? JSON.parse(process.env.REDIS_SENTINELS)
+ : undefined,
+ sentinelPassword:
+ +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINEL_PASSWORD
+ ? process.env.REDIS_SENTINEL_PASSWORD
+ : undefined,
+ role:
+ +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINEL_ROLE
+ ? process.env.REDIS_SENTINEL_ROLE
+ : undefined,
};
// Observe application's life cycle to disconnect the datasource when
@@ -25,13 +41,25 @@ export class RedisDataSource
extends juggler.DataSource
implements LifeCycleObserver
{
- static readonly dataSourceName = AuthCacheSourceName;
+ static dataSourceName = AuthCacheSourceName;
static readonly defaultConfig = config;
constructor(
- @inject('datasources.config.redis', {optional: true})
- dsConfig: object = config,
+ @inject(`datasources.config.${process.env.REDIS_NAME}`, {optional: true})
+ dsConfig: AnyObject = config,
) {
+ if (
+ +process.env.REDIS_HAS_SENTINELS! &&
+ !!process.env.REDIS_SENTINEL_HOST &&
+ !!process.env.REDIS_SENTINEL_PORT
+ ) {
+ dsConfig.sentinels = [
+ {
+ host: process.env.REDIS_SENTINEL_HOST,
+ port: +process.env.REDIS_SENTINEL_PORT,
+ },
+ ];
+ }
super(dsConfig);
}
}
diff --git a/sandbox/oauth-example/src/index.ts b/sandbox/oauth-example/src/index.ts
index dd03ead610..592aa9d4fa 100644
--- a/sandbox/oauth-example/src/index.ts
+++ b/sandbox/oauth-example/src/index.ts
@@ -1,16 +1,11 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import * as dotenv from 'dotenv';
-import {ApplicationConfig, AuthServiceApplication} from './application';
+import {ApplicationConfig, AuthApplication} from './application';
+
export * from './application';
-dotenv.config();
-const port = 3000;
+const PORT = 3000;
export async function main(options: ApplicationConfig = {}) {
- const app = new AuthServiceApplication(options);
+ const app = new AuthApplication(options);
await app.boot();
await app.start();
@@ -25,7 +20,7 @@ if (require.main === module) {
// Run the application
const config = {
rest: {
- port: +(process.env.PORT ?? port),
+ port: +(process.env.PORT ?? PORT),
host: process.env.HOST,
// The `gracePeriodForClose` provides a graceful close for http/https
// servers with keep-alive clients. The default value is `Infinity`
diff --git a/sandbox/oauth-example/src/migrate.ts b/sandbox/oauth-example/src/migrate.ts
deleted file mode 100644
index 384c4e0d35..0000000000
--- a/sandbox/oauth-example/src/migrate.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {AuthServiceApplication} from './application';
-
-export async function migrate(args: string[]) {
- const existingSchema = args.includes('--rebuild') ? 'drop' : 'alter';
- console.log('Migrating schemas (%s existing schema)', existingSchema); //NOSONAR
-
- const app = new AuthServiceApplication();
- await app.boot();
- await app.migrateSchema({existingSchema});
-
- // Connectors usually keep a pool of opened connections,
- // this keeps the process running even after all work is done.
- // We need to exit explicitly.
- process.exit(0);
-}
-
-migrate(process.argv).catch(err => {
- console.error('Cannot migrate database schema', err); //NOSONAR
- process.exit(1);
-});
diff --git a/sandbox/oauth-example/src/models/README.md b/sandbox/oauth-example/src/models/README.md
new file mode 100644
index 0000000000..f5ea972116
--- /dev/null
+++ b/sandbox/oauth-example/src/models/README.md
@@ -0,0 +1,3 @@
+# Models
+
+This directory contains code for models provided by this app.
diff --git a/sandbox/oauth-example/src/models/index.ts b/sandbox/oauth-example/src/models/index.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/sandbox/oauth-example/src/openapi-spec.ts b/sandbox/oauth-example/src/openapi-spec.ts
index 8d0b7b4aae..f5e8141b35 100644
--- a/sandbox/oauth-example/src/openapi-spec.ts
+++ b/sandbox/oauth-example/src/openapi-spec.ts
@@ -1,29 +1,28 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
import {ApplicationConfig} from '@loopback/core';
-import {AuthServiceApplication} from './application';
+import {AuthApplication} from './application';
-const port = 3000;
-const two = 2;
+const ARGV_INDEX = 2;
/**
* Export the OpenAPI spec from the application
*/
async function exportOpenApiSpec(): Promise {
const config: ApplicationConfig = {
rest: {
- port: +(process.env.PORT ?? port),
+ port: +(process.env.PORT ?? 3000),
host: process.env.HOST ?? 'localhost',
},
};
- const outFile = process.argv[two] ?? '';
- const app = new AuthServiceApplication(config);
+ const outFile = process.argv[ARGV_INDEX] ?? './src/openapi.json';
+ const app = new AuthApplication(config);
await app.boot();
await app.exportOpenApiSpec(outFile);
}
-exportOpenApiSpec().catch(err => {
- console.error('Fail to export OpenAPI spec from the application.', err); //NOSONAR
- process.exit(1);
-});
+exportOpenApiSpec()
+ .then(() => {
+ process.exit(0);
+ })
+ .catch(err => {
+ console.error('Fail to export OpenAPI spec from the application.', err);
+ process.exit(1);
+ });
diff --git a/sandbox/oauth-example/src/openapi.json b/sandbox/oauth-example/src/openapi.json
new file mode 100644
index 0000000000..2b15663ddf
--- /dev/null
+++ b/sandbox/oauth-example/src/openapi.json
@@ -0,0 +1,3036 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "auth",
+ "version": "1.0.0",
+ "description": "auth",
+ "contact": {
+ "name": "Tyagi-Sunny",
+ "email": "sunny.tyagi@sourcefuse.com"
+ }
+ },
+ "paths": {
+ "/.well-known/openid-configuration": {
+ "get": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "getConfig",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To get the openid configuration",
+ "responses": {
+ "200": {
+ "description": "OpenId Configuration",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "IdentityServerController.getConfig"
+ }
+ },
+ "/active-users/{range}": {
+ "get": {
+ "x-controller-name": "LoginActivityController",
+ "x-operation-name": "getActiveUsers",
+ "tags": [
+ "LoginActivityController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "LoginActivity model instance",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "description": "\n\n| Permissions |\n| ------- |\n| ViewLoginActivity |\n",
+ "parameters": [
+ {
+ "name": "range",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "startDate",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ {
+ "name": "endDate",
+ "in": "query",
+ "schema": {
+ "type": "string",
+ "format": "date-time"
+ }
+ },
+ {
+ "name": "filter",
+ "in": "query",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": true
+ }
+ }
+ }
+ }
+ ],
+ "operationId": "LoginActivityController.getActiveUsers"
+ }
+ },
+ "/auth/apple-oauth-redirect": {
+ "get": {
+ "x-controller-name": "AppleLoginController",
+ "x-operation-name": "appleCallback",
+ "tags": [
+ "AppleLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Apple Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "AppleLoginController.appleCallback"
+ }
+ },
+ "/auth/auth0": {
+ "post": {
+ "x-controller-name": "Auth0LoginController",
+ "x-operation-name": "postLoginViaAuth0",
+ "tags": [
+ "Auth0LoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for auth0 based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "Auth0LoginController.postLoginViaAuth0"
+ },
+ "get": {
+ "x-controller-name": "Auth0LoginController",
+ "x-operation-name": "loginViaAuth0",
+ "tags": [
+ "Auth0LoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for auth0 based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "deprecated": true,
+ "parameters": [
+ {
+ "name": "client_id",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client_secret",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "Auth0LoginController.loginViaAuth0"
+ }
+ },
+ "/auth/auth0-auth-redirect": {
+ "get": {
+ "x-controller-name": "Auth0LoginController",
+ "x-operation-name": "auth0Callback",
+ "tags": [
+ "Auth0LoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "Auth0LoginController.auth0Callback"
+ }
+ },
+ "/auth/azure": {
+ "post": {
+ "x-controller-name": "AzureLoginController",
+ "x-operation-name": "postLoginViaAzure",
+ "tags": [
+ "AzureLoginController"
+ ],
+ "description": "POST Call for azure based login",
+ "responses": {
+ "200": {
+ "description": "Azure Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "AzureLoginController.postLoginViaAzure"
+ },
+ "get": {
+ "x-controller-name": "AzureLoginController",
+ "x-operation-name": "getLoginViaAzure",
+ "tags": [
+ "AzureLoginController"
+ ],
+ "description": "POST Call for azure based login",
+ "responses": {
+ "200": {
+ "description": "Azure Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "deprecated": true,
+ "parameters": [
+ {
+ "name": "client_id",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client_secret",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "AzureLoginController.getLoginViaAzure"
+ }
+ },
+ "/auth/azure-oauth-redirect": {
+ "get": {
+ "x-controller-name": "AzureLoginController",
+ "x-operation-name": "azureCallback",
+ "tags": [
+ "AzureLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Azure Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "session_state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "AzureLoginController.azureCallback"
+ }
+ },
+ "/auth/change-password": {
+ "patch": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "resetPassword",
+ "tags": [
+ "LoginController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "If User password successfully changed."
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResetPasswordPartial"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.resetPassword"
+ }
+ },
+ "/auth/check-qr-code": {
+ "get": {
+ "x-controller-name": "OtpController",
+ "x-operation-name": "checkQr",
+ "tags": [
+ "OtpController"
+ ],
+ "description": "Returns isGenerated:true if secret_key already exist",
+ "responses": {
+ "200": {
+ "description": "secret_key already exists",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "code",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "clientId",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "OtpController.checkQr"
+ }
+ },
+ "/auth/cognito": {
+ "post": {
+ "x-controller-name": "CognitoLoginController",
+ "x-operation-name": "postLoginViaCognito",
+ "tags": [
+ "CognitoLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for Cognito based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "CognitoLoginController.postLoginViaCognito"
+ },
+ "get": {
+ "x-controller-name": "CognitoLoginController",
+ "x-operation-name": "loginViaCognito",
+ "tags": [
+ "CognitoLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Cognito Token Response (Deprecated: Possible security issue if secret is passed via query params, please use the post endpoint)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "deprecated": true,
+ "parameters": [
+ {
+ "name": "client_id",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client_secret",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "CognitoLoginController.loginViaCognito"
+ }
+ },
+ "/auth/cognito-auth-redirect": {
+ "get": {
+ "x-controller-name": "CognitoLoginController",
+ "x-operation-name": "cognitoCallback",
+ "tags": [
+ "CognitoLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Cognito Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "CognitoLoginController.cognitoCallback"
+ }
+ },
+ "/auth/create-qr-code": {
+ "post": {
+ "x-controller-name": "OtpController",
+ "x-operation-name": "createQr",
+ "tags": [
+ "OtpController"
+ ],
+ "description": "Generates a new qrCode for Authenticator App",
+ "responses": {
+ "200": {
+ "description": "qrCode that you can use to generate codes in Authenticator App",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthTokenRequest"
+ }
+ }
+ }
+ },
+ "operationId": "OtpController.createQr"
+ }
+ },
+ "/auth/facebook": {
+ "post": {
+ "x-controller-name": "FacebookLoginController",
+ "x-operation-name": "postLoginViaFacebook",
+ "tags": [
+ "FacebookLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for Facebook based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "FacebookLoginController.postLoginViaFacebook"
+ }
+ },
+ "/auth/facebook-auth-redirect": {
+ "get": {
+ "x-controller-name": "FacebookLoginController",
+ "x-operation-name": "facebookCallback",
+ "tags": [
+ "FacebookLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Facebook Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "FacebookLoginController.facebookCallback"
+ }
+ },
+ "/auth/forget-password": {
+ "post": {
+ "x-controller-name": "ForgetPasswordController",
+ "x-operation-name": "forgetPassword",
+ "tags": [
+ "ForgetPasswordController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Success Response."
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ForgetPasswordDto"
+ }
+ }
+ }
+ },
+ "operationId": "ForgetPasswordController.forgetPassword"
+ }
+ },
+ "/auth/google": {
+ "post": {
+ "x-controller-name": "GoogleLoginController",
+ "x-operation-name": "postLoginViaGoogle",
+ "tags": [
+ "GoogleLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for Google based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "GoogleLoginController.postLoginViaGoogle"
+ },
+ "get": {
+ "x-controller-name": "GoogleLoginController",
+ "x-operation-name": "loginViaGoogle",
+ "tags": [
+ "GoogleLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Google Token Response,\n (Deprecated: Possible security issue if secret is passed via query params,\n please use the post endpoint)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "deprecated": true,
+ "parameters": [
+ {
+ "name": "client_id",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client_secret",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "GoogleLoginController.loginViaGoogle"
+ }
+ },
+ "/auth/google-auth-redirect": {
+ "get": {
+ "x-controller-name": "GoogleLoginController",
+ "x-operation-name": "googleCallback",
+ "tags": [
+ "GoogleLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Google Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "GoogleLoginController.googleCallback"
+ }
+ },
+ "/auth/instagram": {
+ "post": {
+ "x-controller-name": "InstagramLoginController",
+ "x-operation-name": "postLoginViaInstagram",
+ "tags": [
+ "InstagramLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for Instagram based login",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "InstagramLoginController.postLoginViaInstagram"
+ }
+ },
+ "/auth/instagram-auth-redirect": {
+ "get": {
+ "x-controller-name": "InstagramLoginController",
+ "x-operation-name": "instagramCallback",
+ "tags": [
+ "InstagramLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Instagram Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "InstagramLoginController.instagramCallback"
+ }
+ },
+ "/auth/keycloak": {
+ "post": {
+ "x-controller-name": "KeycloakLoginController",
+ "x-operation-name": "postLoginViaKeycloak",
+ "tags": [
+ "KeycloakLoginController"
+ ],
+ "description": "POST Call for keycloak based login",
+ "responses": {
+ "200": {
+ "description": "Keycloak Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "KeycloakLoginController.postLoginViaKeycloak"
+ },
+ "get": {
+ "x-controller-name": "KeycloakLoginController",
+ "x-operation-name": "loginViaKeycloak",
+ "tags": [
+ "KeycloakLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Keycloak Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "deprecated": true,
+ "parameters": [
+ {
+ "name": "client_id",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "client_secret",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "KeycloakLoginController.loginViaKeycloak"
+ }
+ },
+ "/auth/keycloak-auth-redirect": {
+ "get": {
+ "x-controller-name": "KeycloakLoginController",
+ "x-operation-name": "keycloakCallback",
+ "tags": [
+ "KeycloakLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Keycloak Redirect Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "code",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "state",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "operationId": "KeycloakLoginController.keycloakCallback"
+ }
+ },
+ "/auth/login": {
+ "post": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "login",
+ "tags": [
+ "LoginController"
+ ],
+ "description": "Gets you the code that will be used for getting token (webapps)",
+ "responses": {
+ "200": {
+ "description": "Auth Code that you can use to generate access and refresh tokens using the POST /auth/token API",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginRequest"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.login"
+ }
+ },
+ "/auth/login-token": {
+ "post": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "loginWithClientUser",
+ "tags": [
+ "LoginController"
+ ],
+ "description": "Gets you refresh token and access token in one hit. (mobile app)",
+ "responses": {
+ "200": {
+ "description": "Token Response Model",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "deprecated": true,
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginRequest"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.loginWithClientUser"
+ }
+ },
+ "/auth/me": {
+ "get": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "me",
+ "tags": [
+ "LoginController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To get the user details",
+ "responses": {
+ "200": {
+ "description": "User Object",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "LoginController.me"
+ }
+ },
+ "/auth/oauth-apple": {
+ "post": {
+ "x-controller-name": "AppleLoginController",
+ "x-operation-name": "postLoginViaApple",
+ "tags": [
+ "AppleLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "POST Call for Apple based login",
+ "content": {}
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "AppleLoginController.postLoginViaApple"
+ }
+ },
+ "/auth/reset-password": {
+ "patch": {
+ "x-controller-name": "ForgetPasswordController",
+ "x-operation-name": "resetPassword",
+ "tags": [
+ "ForgetPasswordController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "If User password successfully changed."
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResetPasswordWithClient"
+ }
+ }
+ }
+ },
+ "operationId": "ForgetPasswordController.resetPassword"
+ }
+ },
+ "/auth/saml": {
+ "post": {
+ "x-controller-name": "SamlLoginController",
+ "x-operation-name": "postLoginViaSaml",
+ "tags": [
+ "SamlLoginController"
+ ],
+ "description": "POST Call for saml based login",
+ "responses": {
+ "200": {
+ "description": "Saml Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/ClientAuthRequest"
+ }
+ }
+ }
+ },
+ "operationId": "SamlLoginController.postLoginViaSaml"
+ }
+ },
+ "/auth/saml-redirect": {
+ "post": {
+ "x-controller-name": "SamlLoginController",
+ "x-operation-name": "oktaSamlCallback",
+ "tags": [
+ "SamlLoginController"
+ ],
+ "responses": {
+ "200": {
+ "description": "okta auth callback",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "client",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "SamlLoginController.oktaSamlCallback"
+ }
+ },
+ "/auth/send-otp": {
+ "post": {
+ "x-controller-name": "OtpController",
+ "x-operation-name": "sendOtp",
+ "tags": [
+ "OtpController"
+ ],
+ "description": "Sends OTP",
+ "responses": {
+ "200": {
+ "description": "Sends otp to user",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/OtpSendRequest"
+ }
+ }
+ }
+ },
+ "operationId": "OtpController.sendOtp"
+ }
+ },
+ "/auth/sign-up/create-token": {
+ "post": {
+ "x-controller-name": "SignupRequestController",
+ "x-operation-name": "requestSignup",
+ "tags": [
+ "SignupRequestController"
+ ],
+ "responses": {
+ "204": {
+ "description": "Sucess Response."
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SignupRequestDto"
+ }
+ }
+ }
+ },
+ "operationId": "SignupRequestController.requestSignup"
+ }
+ },
+ "/auth/sign-up/create-user": {
+ "post": {
+ "x-controller-name": "SignupRequestController",
+ "x-operation-name": "signupWithToken",
+ "tags": [
+ "SignupRequestController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Sucess Response.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LocalUserProfileDto"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "description": "",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LocalUserProfileDto"
+ }
+ }
+ }
+ },
+ "operationId": "SignupRequestController.signupWithToken"
+ }
+ },
+ "/auth/sign-up/verify-token": {
+ "get": {
+ "x-controller-name": "SignupRequestController",
+ "x-operation-name": "verifyInviteToken",
+ "tags": [
+ "SignupRequestController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Sucess Response."
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "description": "",
+ "operationId": "SignupRequestController.verifyInviteToken"
+ }
+ },
+ "/auth/switch-token": {
+ "post": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "switchToken",
+ "tags": [
+ "LoginController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To switch the access-token",
+ "responses": {
+ "200": {
+ "description": "Switch access token with the tenant id provided.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthRefreshTokenRequest"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.switchToken"
+ }
+ },
+ "/auth/token": {
+ "post": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "getToken",
+ "tags": [
+ "LoginController"
+ ],
+ "description": "Send the code received from the POST /auth/login api and get refresh token and access token (webapps)",
+ "responses": {
+ "200": {
+ "description": "Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthTokenRequest"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.getToken"
+ }
+ },
+ "/auth/token-refresh": {
+ "post": {
+ "x-controller-name": "LoginController",
+ "x-operation-name": "exchangeToken",
+ "tags": [
+ "LoginController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "Gets you a new access and refresh token once your access token is expired",
+ "responses": {
+ "200": {
+ "description": "New Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "device_id",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthRefreshTokenRequest"
+ }
+ }
+ }
+ },
+ "operationId": "LoginController.exchangeToken"
+ }
+ },
+ "/auth/verify-otp": {
+ "post": {
+ "x-controller-name": "OtpController",
+ "x-operation-name": "verifyOtp",
+ "tags": [
+ "OtpController"
+ ],
+ "description": "Gets you the code that will be used for getting token (webapps)",
+ "responses": {
+ "200": {
+ "description": "Auth Code that you can use to generate access and refresh tokens using the POST /auth/token API",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/OtpLoginRequest"
+ }
+ }
+ }
+ },
+ "operationId": "OtpController.verifyOtp"
+ }
+ },
+ "/auth/verify-reset-password-link": {
+ "get": {
+ "x-controller-name": "ForgetPasswordController",
+ "x-operation-name": "verifyResetPasswordLink",
+ "tags": [
+ "ForgetPasswordController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Check if Token Is Valid and not Expired."
+ }
+ },
+ "description": "",
+ "parameters": [
+ {
+ "name": "token",
+ "in": "query",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "operationId": "ForgetPasswordController.verifyResetPasswordLink"
+ }
+ },
+ "/cognito/logout": {
+ "post": {
+ "x-controller-name": "LogoutController",
+ "x-operation-name": "cognitoLogout",
+ "tags": [
+ "LogoutController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "This API will log out the user from application as well as cognito",
+ "responses": {
+ "200": {
+ "description": "Success Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SuccessResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ },
+ "description": "This is the access token which is required to authenticate user."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RefreshTokenRequestPartial"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "LogoutController.cognitoLogout"
+ }
+ },
+ "/connect/endsession": {
+ "post": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "logout",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To logout",
+ "responses": {
+ "200": {
+ "description": "Success Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SuccessResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ },
+ "description": "This is the access token which is required to authenticate user."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthRefreshTokenRequestPartial"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "IdentityServerController.logout"
+ }
+ },
+ "/connect/generate-keys": {
+ "post": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "generateKeys",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "description": "Generate the set of public and private keys",
+ "responses": {
+ "200": {
+ "description": "JWKS Keys"
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "IdentityServerController.generateKeys"
+ }
+ },
+ "/connect/get-keys": {
+ "get": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "getKeys",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "description": "Get the public keys",
+ "responses": {
+ "200": {
+ "description": "JWKS Keys"
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "IdentityServerController.getKeys"
+ }
+ },
+ "/connect/rotate-keys": {
+ "post": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "rotateKeys",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "description": "Generate the set of public and private keys",
+ "responses": {
+ "200": {
+ "description": "JWKS Keys"
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "IdentityServerController.rotateKeys"
+ }
+ },
+ "/connect/token": {
+ "post": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "getToken",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "description": "Send the code received from the POST /auth/login api and get refresh token and access token (webapps)",
+ "responses": {
+ "200": {
+ "description": "Token Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TokenResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/AuthTokenRequest"
+ }
+ }
+ }
+ },
+ "operationId": "IdentityServerController.getToken"
+ }
+ },
+ "/connect/userinfo": {
+ "get": {
+ "x-controller-name": "IdentityServerController",
+ "x-operation-name": "me",
+ "tags": [
+ "IdentityServerController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To get the user details",
+ "responses": {
+ "200": {
+ "description": "User Object",
+ "content": {}
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "operationId": "IdentityServerController.me"
+ }
+ },
+ "/google/logout": {
+ "post": {
+ "x-controller-name": "LogoutController",
+ "x-operation-name": "googleLogout",
+ "tags": [
+ "LogoutController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "This API will log out the user from application as well as google",
+ "responses": {
+ "200": {
+ "description": "Success Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SuccessResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ },
+ "description": "This is the access token which is required to authenticate user."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RefreshTokenRequestPartial"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "LogoutController.googleLogout"
+ }
+ },
+ "/keycloak/logout": {
+ "post": {
+ "x-controller-name": "LogoutController",
+ "x-operation-name": "keycloakLogout",
+ "tags": [
+ "LogoutController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "This API will log out the user from application as well as keycloak",
+ "responses": {
+ "200": {
+ "description": "Success Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SuccessResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ },
+ "description": "This is the access token which is required to authenticate user."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RefreshTokenRequestPartial"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "LogoutController.keycloakLogout"
+ }
+ },
+ "/login-activity/count": {
+ "get": {
+ "x-controller-name": "LoginActivityController",
+ "x-operation-name": "count",
+ "tags": [
+ "LoginActivityController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "LoginActivity model count",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/loopback.Count"
+ }
+ }
+ }
+ }
+ },
+ "description": "\n\n| Permissions |\n| ------- |\n| ViewLoginActivity |\n",
+ "parameters": [
+ {
+ "name": "where",
+ "in": "query",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "title": "login_activity.WhereFilter",
+ "additionalProperties": true,
+ "x-typescript-type": "@loopback/repository#Where"
+ }
+ }
+ }
+ }
+ ],
+ "operationId": "LoginActivityController.count"
+ }
+ },
+ "/login-activity/{id}": {
+ "get": {
+ "x-controller-name": "LoginActivityController",
+ "x-operation-name": "findById",
+ "tags": [
+ "LoginActivityController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "LoginActivity model instance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LoginActivityWithRelations"
+ }
+ }
+ }
+ }
+ },
+ "description": "\n\n| Permissions |\n| ------- |\n| ViewLoginActivity |\n",
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ },
+ {
+ "name": "filter",
+ "in": "query",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/login_activity.Filter"
+ }
+ }
+ }
+ }
+ ],
+ "operationId": "LoginActivityController.findById"
+ }
+ },
+ "/login-activity": {
+ "get": {
+ "x-controller-name": "LoginActivityController",
+ "x-operation-name": "find",
+ "tags": [
+ "LoginActivityController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Array of LoginActivity model instances",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/LoginActivityWithRelations"
+ }
+ }
+ }
+ }
+ }
+ },
+ "description": "\n\n| Permissions |\n| ------- |\n| ViewLoginActivity |\n",
+ "parameters": [
+ {
+ "name": "filter",
+ "in": "query",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/login_activity.Filter"
+ }
+ }
+ }
+ }
+ ],
+ "operationId": "LoginActivityController.find"
+ }
+ },
+ "/logout": {
+ "post": {
+ "x-controller-name": "LogoutController",
+ "x-operation-name": "logout",
+ "tags": [
+ "LogoutController"
+ ],
+ "security": [
+ {
+ "HTTPBearer": []
+ }
+ ],
+ "description": "To logout",
+ "responses": {
+ "200": {
+ "description": "Success Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SuccessResponse"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The syntax of the request entity is incorrect."
+ },
+ "401": {
+ "description": "Invalid Credentials."
+ },
+ "404": {
+ "description": "The entity requested does not exist."
+ },
+ "422": {
+ "description": "The syntax of the request entity is incorrect"
+ }
+ },
+ "parameters": [
+ {
+ "name": "Authorization",
+ "in": "header",
+ "schema": {
+ "type": "string"
+ },
+ "description": "This is the access token which is required to authenticate user."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RefreshTokenRequestPartial"
+ }
+ }
+ },
+ "x-parameter-index": 1
+ },
+ "operationId": "LogoutController.logout"
+ }
+ },
+ "/ping": {
+ "get": {
+ "x-controller-name": "PingController",
+ "x-operation-name": "ping",
+ "tags": [
+ "PingController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Ping Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PingResponse"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "operationId": "PingController.ping"
+ }
+ },
+ "/": {
+ "get": {
+ "x-controller-name": "HomePageController",
+ "x-operation-name": "homePage",
+ "tags": [
+ "HomePageController"
+ ],
+ "responses": {
+ "200": {
+ "description": "Home Page",
+ "content": {
+ "text/html": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "description": "",
+ "operationId": "HomePageController.homePage"
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "HTTPBearer": {
+ "type": "http",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ }
+ },
+ "schemas": {
+ "LoginRequest": {
+ "title": "LoginRequest",
+ "type": "object",
+ "description": "This is the signature for login request.",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "client_secret": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "username": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "password": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ }
+ },
+ "required": [
+ "client_id",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ "TokenResponse": {
+ "title": "TokenResponse",
+ "type": "object",
+ "description": "This is signature for successful token response.",
+ "properties": {
+ "accessToken": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "refreshToken": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "expires": {
+ "type": "number"
+ },
+ "pubnubToken": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "accessToken",
+ "refreshToken",
+ "expires"
+ ],
+ "additionalProperties": false
+ },
+ "AuthTokenRequest": {
+ "title": "AuthTokenRequest",
+ "type": "object",
+ "description": "This is the signature for requesting the accessToken and refreshToken.",
+ "properties": {
+ "code": {
+ "type": "string"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "code",
+ "clientId"
+ ],
+ "additionalProperties": false
+ },
+ "AuthRefreshTokenRequest": {
+ "title": "AuthRefreshTokenRequest",
+ "type": "object",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ },
+ "tenantId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "refreshToken"
+ ],
+ "additionalProperties": false
+ },
+ "ResetPasswordPartial": {
+ "title": "ResetPasswordPartial",
+ "type": "object",
+ "description": "This is a signature for reset password. (tsType: Partial, schemaOptions: { partial: true })",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "password": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "oldPassword": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ }
+ },
+ "additionalProperties": false
+ },
+ "ResetPassword": {
+ "title": "ResetPassword",
+ "type": "object",
+ "description": "This is a signature for reset password.",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "password": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "oldPassword": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ }
+ },
+ "required": [
+ "refreshToken",
+ "username",
+ "password"
+ ],
+ "additionalProperties": false
+ },
+ "ClientAuthRequest": {
+ "title": "ClientAuthRequest",
+ "type": "object",
+ "description": "This is signature for client authentication request.",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "client_secret": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ }
+ },
+ "required": [
+ "client_id",
+ "client_secret"
+ ],
+ "additionalProperties": false
+ },
+ "SuccessResponse": {
+ "title": "SuccessResponse",
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": true
+ },
+ "RefreshTokenRequestPartial": {
+ "title": "RefreshTokenRequestPartial",
+ "type": "object",
+ "description": "(tsType: Partial, schemaOptions: { partial: true })",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "x-typescript-type": "Partial"
+ },
+ "RefreshTokenRequest": {
+ "title": "RefreshTokenRequest",
+ "type": "object",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "refreshToken"
+ ],
+ "additionalProperties": false
+ },
+ "OtpSendRequest": {
+ "title": "OtpSendRequest",
+ "type": "object",
+ "description": "This is the signature for OTP login request.",
+ "properties": {
+ "client_id": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "client_secret": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "key": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ }
+ },
+ "required": [
+ "client_id",
+ "client_secret",
+ "key"
+ ],
+ "additionalProperties": false
+ },
+ "OtpLoginRequest": {
+ "title": "OtpLoginRequest",
+ "type": "object",
+ "description": "This is the signature for OTP login request.",
+ "properties": {
+ "key": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "otp": {
+ "type": "string",
+ "description": "This property is supposed to be a string and is a required field"
+ },
+ "clientId": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "key",
+ "otp"
+ ],
+ "additionalProperties": false
+ },
+ "AuthUser": {
+ "title": "AuthUser",
+ "type": "object",
+ "description": "This is the signature for authenticated user which holds permissions and role.",
+ "properties": {
+ "deleted": {
+ "type": "boolean"
+ },
+ "deletedOn": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "deletedBy": {
+ "type": "string",
+ "nullable": true
+ },
+ "createdOn": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "modifiedOn": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "createdBy": {
+ "type": "string"
+ },
+ "modifiedBy": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "middleName": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string"
+ },
+ "phone": {
+ "type": "string",
+ "pattern": "^\\+?[1-9]\\d{1,14}$"
+ },
+ "authClientIds": {
+ "type": "string"
+ },
+ "lastLogin": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "photoUrl": {
+ "type": "string"
+ },
+ "designation": {
+ "type": "string"
+ },
+ "dob": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "gender": {
+ "type": "string",
+ "description": "This field takes a single character as input in database.\n 'M' for male and 'F' for female.",
+ "enum": [
+ "M",
+ "F",
+ "O"
+ ]
+ },
+ "defaultTenantId": {
+ "type": "string"
+ },
+ "permissions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "role": {
+ "type": "string"
+ },
+ "externalAuthToken": {
+ "type": "string"
+ },
+ "deviceInfo": {
+ "type": "object",
+ "description": "This property consists of two optional fields.\n 1. userAgent\n 2. deviceId "
+ },
+ "age": {
+ "type": "number"
+ },
+ "externalRefreshToken": {
+ "type": "string"
+ },
+ "authClientId": {
+ "type": "number"
+ },
+ "userPreferences": {
+ "type": "object"
+ },
+ "tenantId": {
+ "type": "string"
+ },
+ "userTenantId": {
+ "type": "string"
+ },
+ "passwordExpiryTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "status": {
+ "type": "number",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 0,
+ 4
+ ]
+ }
+ },
+ "required": [
+ "firstName",
+ "username",
+ "role"
+ ],
+ "additionalProperties": false
+ },
+ "Function": {},
+ "ForgetPasswordDto": {
+ "title": "ForgetPasswordDto",
+ "type": "object",
+ "properties": {
+ "username": {
+ "type": "string"
+ },
+ "client_id": {
+ "type": "string"
+ },
+ "client_secret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "username",
+ "client_id",
+ "client_secret"
+ ],
+ "additionalProperties": false
+ },
+ "AuthClient": {
+ "title": "AuthClient",
+ "type": "object",
+ "properties": {
+ "deleted": {
+ "type": "boolean"
+ },
+ "deletedOn": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "deletedBy": {
+ "type": "string",
+ "nullable": true
+ },
+ "createdOn": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "modifiedOn": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "createdBy": {
+ "type": "string"
+ },
+ "modifiedBy": {
+ "type": "string"
+ },
+ "id": {
+ "type": "number"
+ },
+ "clientId": {
+ "type": "string"
+ },
+ "clientSecret": {
+ "type": "string"
+ },
+ "secret": {
+ "type": "string",
+ "description": "Value can be a string or a private key."
+ },
+ "redirectUrl": {
+ "type": "string"
+ },
+ "accessTokenExpiration": {
+ "type": "number"
+ },
+ "refreshTokenExpiration": {
+ "type": "number"
+ },
+ "authCodeExpiration": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "clientId",
+ "clientSecret",
+ "secret",
+ "accessTokenExpiration",
+ "refreshTokenExpiration",
+ "authCodeExpiration"
+ ],
+ "additionalProperties": false
+ },
+ "ResetPasswordWithClient": {
+ "title": "ResetPasswordWithClient",
+ "type": "object",
+ "properties": {
+ "token": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "client_id": {
+ "type": "string"
+ },
+ "client_secret": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "token",
+ "password",
+ "client_id",
+ "client_secret"
+ ],
+ "additionalProperties": false
+ },
+ "SignupRequestDto": {
+ "title": "SignupRequestDto",
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "data": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "email"
+ ],
+ "additionalProperties": false
+ },
+ "LocalUserProfileDto": {
+ "title": "LocalUserProfileDto",
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "email",
+ "password"
+ ],
+ "additionalProperties": true
+ },
+ "SignupRequest": {
+ "title": "SignupRequest",
+ "type": "object",
+ "properties": {
+ "email": {
+ "type": "string"
+ },
+ "expiry": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "email"
+ ],
+ "additionalProperties": false
+ },
+ "LoginActivityWithRelations": {
+ "title": "LoginActivityWithRelations",
+ "type": "object",
+ "description": "This is to maintain the daily login activity. (tsType: LoginActivityWithRelations, schemaOptions: { includeRelations: true })",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "actor": {
+ "type": "string"
+ },
+ "tenantId": {
+ "type": "string"
+ },
+ "loginTime": {
+ "type": "string",
+ "format": "date-time"
+ },
+ "tokenPayload": {
+ "type": "string"
+ },
+ "loginType": {
+ "type": "string"
+ },
+ "deviceInfo": {
+ "type": "string"
+ },
+ "ipAddress": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ },
+ "Date": {},
+ "ActiveUsersFilter": {
+ "title": "ActiveUsersFilter",
+ "type": "object",
+ "properties": {
+ "inclusion": {
+ "type": "boolean"
+ },
+ "userIdentity": {
+ "type": "string"
+ },
+ "userIdentifier": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "inclusion",
+ "userIdentity",
+ "userIdentifier"
+ ],
+ "additionalProperties": false
+ },
+ "AuthRefreshTokenRequestPartial": {
+ "title": "AuthRefreshTokenRequestPartial",
+ "type": "object",
+ "description": "(tsType: Partial, schemaOptions: { partial: true })",
+ "properties": {
+ "refreshToken": {
+ "type": "string"
+ },
+ "tenantId": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false,
+ "x-typescript-type": "Partial"
+ },
+ "loopback.Count": {
+ "type": "object",
+ "title": "loopback.Count",
+ "x-typescript-type": "@loopback/repository#Count",
+ "properties": {
+ "count": {
+ "type": "number"
+ }
+ }
+ },
+ "login_activity.Filter": {
+ "type": "object",
+ "title": "login_activity.Filter",
+ "properties": {
+ "offset": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "limit": {
+ "type": "integer",
+ "minimum": 1,
+ "example": 100
+ },
+ "skip": {
+ "type": "integer",
+ "minimum": 0
+ },
+ "order": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ ]
+ },
+ "where": {
+ "title": "login_activity.WhereFilter",
+ "type": "object",
+ "additionalProperties": true
+ },
+ "fields": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "boolean"
+ },
+ "actor": {
+ "type": "boolean"
+ },
+ "tenantId": {
+ "type": "boolean"
+ },
+ "loginTime": {
+ "type": "boolean"
+ },
+ "tokenPayload": {
+ "type": "boolean"
+ },
+ "loginType": {
+ "type": "boolean"
+ },
+ "deviceInfo": {
+ "type": "boolean"
+ },
+ "ipAddress": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "id",
+ "actor",
+ "tenantId",
+ "loginTime",
+ "tokenPayload",
+ "loginType",
+ "deviceInfo",
+ "ipAddress"
+ ],
+ "example": "id"
+ },
+ "uniqueItems": true
+ }
+ ],
+ "title": "login_activity.Fields"
+ }
+ },
+ "additionalProperties": false,
+ "x-typescript-type": "@loopback/repository#Filter"
+ },
+ "PingResponse": {
+ "type": "object",
+ "title": "PingResponse",
+ "properties": {
+ "greeting": {
+ "type": "string"
+ },
+ "date": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "headers": {
+ "type": "object",
+ "properties": {
+ "Content-Type": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": true
+ }
+ }
+ }
+ }
+ },
+ "servers": [
+ {
+ "url": "/"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/sandbox/oauth-example/src/opentelemetry-registry.ts b/sandbox/oauth-example/src/opentelemetry-registry.ts
new file mode 100644
index 0000000000..02aef44196
--- /dev/null
+++ b/sandbox/oauth-example/src/opentelemetry-registry.ts
@@ -0,0 +1,31 @@
+import {JaegerExporter} from '@opentelemetry/exporter-jaeger';
+import {NodeTracerProvider} from '@opentelemetry/sdk-trace-node';
+import {
+ BatchSpanProcessor,
+ ConsoleSpanExporter,
+} from '@opentelemetry/sdk-trace-base';
+import * as dotenv from 'dotenv';
+import * as dotenvExt from 'dotenv-extended';
+
+dotenv.config();
+dotenvExt.load({
+ schema: '.env.example',
+ errorOnMissing: true,
+ includeProcessEnv: true,
+});
+
+if (!!+(process.env.ENABLE_TRACING ?? 0)) {
+ const provider = new NodeTracerProvider();
+ const option = {
+ serviceName: process.env.SERVICE_NAME ?? '',
+ tags: [],
+ // You can use the default UDPSender
+ host: process.env.OPENTELEMETRY_HOST ?? '',
+ port: process.env.OPENTELEMETRY_PORT ? +process.env.OPENTELEMETRY_PORT : 0,
+ };
+ // Configure span processor to send spans to the exporter
+ const exporter = new JaegerExporter(option);
+ provider.addSpanProcessor(new BatchSpanProcessor(exporter));
+ provider.addSpanProcessor(new BatchSpanProcessor(new ConsoleSpanExporter()));
+ provider.register();
+}
diff --git a/sandbox/oauth-example/src/providers/azure-ad-signup.provider.ts b/sandbox/oauth-example/src/providers/azure-ad-signup.provider.ts
deleted file mode 100644
index bdc726083c..0000000000
--- a/sandbox/oauth-example/src/providers/azure-ad-signup.provider.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {Provider} from '@loopback/context';
-import {repository} from '@loopback/repository';
-import {HttpErrors} from '@loopback/rest';
-import {
- AuthClientRepository,
- AzureAdSignUpFn,
- User,
- UserRelations,
-} from '@sourceloop/authentication-service';
-import {
- RoleRepository,
- TenantRepository,
- UserRepository,
-} from '../repositories';
-
-export class AzureAdSignupProvider implements Provider {
- constructor(
- @repository(RoleRepository)
- private readonly roleRepo: RoleRepository,
- @repository(TenantRepository)
- private readonly tenantRepo: TenantRepository,
- @repository(AuthClientRepository)
- private readonly authClientRepo: AuthClientRepository,
- @repository(UserRepository)
- private readonly userRepo: UserRepository,
- ) {}
-
- value(): AzureAdSignUpFn {
- return async profile => {
- const [tenant, role, client] = await Promise.all([
- this.tenantRepo.findOne({
- where: {
- key: 'master',
- },
- }),
- this.roleRepo.findOne({
- where: {
- roleType: 0,
- },
- }),
- this.authClientRepo.findOne({
- where: {
- clientId: 'test_client_id',
- },
- }),
- ]);
-
- // check if user exist
-
- const userExists = await this.userRepo.findOne({
- where: {
- or: [{username: profile.upn}, {email: profile.upn}],
- },
- });
- if (userExists) {
- throw new HttpErrors.BadRequest('User already exists');
- }
-
- const user = await this.userRepo.createWithoutPassword({
- firstName: profile.name!.givenName,
- lastName: profile.name!.familyName,
- username: profile.upn,
- email: profile.upn,
- defaultTenantId: tenant?.id,
- authClientIds: `{${client?.id}}`,
- });
-
- await this.userRepo.credentials(user.id).create({
- userId: user.id,
- authProvider: 'azure',
- authId: profile.oid,
- });
-
- await this.userRepo.userTenants(user.id).create({
- userId: user.id,
- tenantId: tenant?.id,
- roleId: role?.id,
- });
- return user as User & UserRelations;
- };
- }
-}
diff --git a/sandbox/oauth-example/src/providers/facebook-oauth2-signup.provider.ts b/sandbox/oauth-example/src/providers/facebook-oauth2-signup.provider.ts
deleted file mode 100644
index 36b1b61e33..0000000000
--- a/sandbox/oauth-example/src/providers/facebook-oauth2-signup.provider.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {Provider} from '@loopback/context';
-import {repository} from '@loopback/repository';
-import {HttpErrors} from '@loopback/rest';
-import {
- AuthClientRepository,
- FacebookSignUpFn,
- User,
- UserRelations,
-} from '@sourceloop/authentication-service';
-import {
- RoleRepository,
- TenantRepository,
- UserRepository,
-} from '../repositories';
-
-export class FacebookOauth2SignupProvider
- implements Provider
-{
- constructor(
- @repository(RoleRepository)
- private readonly roleRepo: RoleRepository,
- @repository(TenantRepository)
- private readonly tenantRepo: TenantRepository,
- @repository(AuthClientRepository)
- private readonly authClientRepo: AuthClientRepository,
- @repository(UserRepository)
- private readonly userRepo: UserRepository,
- ) {}
-
- value(): FacebookSignUpFn {
- return async profile => {
- const [tenant, role, client] = await Promise.all([
- this.tenantRepo.findOne({
- where: {
- key: 'master',
- },
- }),
- this.roleRepo.findOne({
- where: {
- roleType: 0,
- },
- }),
- this.authClientRepo.findOne({
- where: {
- clientId: 'test_client_id',
- },
- }),
- ]);
-
- // check if user exist
-
- const userExists = await this.userRepo.findOne({
- where: {
- or: [{username: profile._json.email}, {email: profile._json.email}],
- },
- });
- if (userExists) {
- throw new HttpErrors.BadRequest('User already exists');
- }
-
- const user = await this.userRepo.createWithoutPassword({
- firstName: profile.name!.givenName ?? profile.displayName,
- lastName: profile.name!.familyName,
- username: profile._json.email ?? profile.displayName,
- email: profile._json.email,
- defaultTenantId: tenant?.id,
- authClientIds: `{${client?.id}}`,
- });
-
- await this.userRepo.credentials(user.id).create({
- userId: user.id,
- authProvider: 'facebook',
- authId: profile.id,
- });
-
- await this.userRepo.userTenants(user.id).create({
- userId: user.id,
- tenantId: tenant?.id,
- roleId: role?.id,
- });
- return user as User & UserRelations;
- };
- }
-}
diff --git a/sandbox/oauth-example/src/providers/google-oauth2-signup.provider.ts b/sandbox/oauth-example/src/providers/google-oauth2-signup.provider.ts
index 4542318deb..90253d6ab7 100644
--- a/sandbox/oauth-example/src/providers/google-oauth2-signup.provider.ts
+++ b/sandbox/oauth-example/src/providers/google-oauth2-signup.provider.ts
@@ -1,4 +1,4 @@
-// Copyright (c) 2023 Sourcefuse Technologies
+// Copyright (c) 2022 Sourcefuse Technologies
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
@@ -8,14 +8,17 @@ import {HttpErrors} from '@loopback/rest';
import {
AuthClientRepository,
GoogleSignUpFn,
- User,
- UserRelations,
-} from '@sourceloop/authentication-service';
-import {
RoleRepository,
TenantRepository,
+ User,
+ UserRelations,
UserRepository,
-} from '../repositories';
+} from '@sourceloop/authentication-service';
+// import {
+// RoleRepository,
+// TenantRepository,
+// UserRepository,
+// } from '../repositories';
export class GoogleOauth2SignupProvider implements Provider {
constructor(
@@ -61,8 +64,8 @@ export class GoogleOauth2SignupProvider implements Provider {
}
const user = await this.userRepo.createWithoutPassword({
- firstName: profile.name!.givenName,
- lastName: profile.name!.familyName,
+ firstName: profile.name.givenName,
+ lastName: profile.name.familyName,
username: profile._json.email,
email: profile._json.email,
defaultTenantId: tenant?.id,
diff --git a/sandbox/oauth-example/src/providers/index.ts b/sandbox/oauth-example/src/providers/index.ts
index e450690a57..befaf40a1e 100644
--- a/sandbox/oauth-example/src/providers/index.ts
+++ b/sandbox/oauth-example/src/providers/index.ts
@@ -1,9 +1 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-export * from './azure-ad-signup.provider';
-export * from './facebook-oauth2-signup.provider';
export * from './google-oauth2-signup.provider';
-export * from './saml-signup.provider';
-export * from './saml-verify.provider';
diff --git a/sandbox/oauth-example/src/providers/saml-signup.provider.ts b/sandbox/oauth-example/src/providers/saml-signup.provider.ts
deleted file mode 100644
index 5d38998cd4..0000000000
--- a/sandbox/oauth-example/src/providers/saml-signup.provider.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import {inject, Provider} from '@loopback/context';
-import {repository} from '@loopback/repository';
-import {HttpErrors} from '@loopback/rest';
-import {
- AuthClient,
- AuthClientRepository,
- SamlSignUpFn,
- TenantRepository,
- User,
- UserCredentialsRepository,
- UserRelations,
- UserRepository,
-} from '@sourceloop/authentication-service';
-import {AuthenticationBindings} from 'loopback4-authentication';
-import {RoleRepository} from '../repositories';
-
-export class SamlSignupProvider implements Provider {
- constructor(
- @repository(UserRepository)
- public userRepository: UserRepository,
- @repository(TenantRepository)
- public tenantRepository: TenantRepository,
- @repository(UserCredentialsRepository)
- public userCredsRepository: UserCredentialsRepository,
- @repository(RoleRepository)
- private readonly roleRepo: RoleRepository,
- @repository(TenantRepository)
- private readonly tenantRepo: TenantRepository,
- @repository(UserRepository)
- private readonly userRepo: UserRepository,
- @repository(AuthClientRepository)
- private readonly authClientRepo: AuthClientRepository,
- @inject(AuthenticationBindings.CURRENT_CLIENT)
- private readonly client: AuthClient | undefined,
- ) {}
-
- value(): SamlSignUpFn {
- return async profile => {
- // Find 1st tenant associated with this client_id
- const [tenant, role, client] = await Promise.all([
- this.tenantRepo.findOne({
- where: {
- key: 'master',
- },
- }),
- this.roleRepo.findOne({
- where: {
- roleType: 0,
- },
- }),
- this.authClientRepo.findOne({
- where: {
- clientId: 'test_client_id',
- },
- }),
- ]);
-
- const userExists = await this.userRepo.findOne({
- where: {
- or: [{username: profile.email}, {email: profile.email}],
- },
- });
- if (userExists) {
- throw new HttpErrors.BadRequest('User already exists');
- }
- const user = await this.userRepo.createWithoutPassword({
- username: profile.email,
- firstName: String(profile.first_name),
- lastName: String(profile.last_name),
- email: profile.email,
- defaultTenantId: tenant?.id,
- authClientIds: `{${client?.id}}`,
- });
-
- await this.userRepo.credentials(user.id).create({
- userId: user.id,
- authProvider: 'saml',
- authId: profile.ID,
- });
-
- await this.userRepo.userTenants(user.id).create({
- userId: user.id,
- tenantId: tenant?.id,
- roleId: role?.id,
- });
- return user as User & UserRelations; // NOSONAR
- };
- }
-}
diff --git a/sandbox/oauth-example/src/providers/saml-verify.provider.ts b/sandbox/oauth-example/src/providers/saml-verify.provider.ts
deleted file mode 100644
index 89901a54e0..0000000000
--- a/sandbox/oauth-example/src/providers/saml-verify.provider.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import {inject, Provider} from '@loopback/context';
-import {repository} from '@loopback/repository';
-import {HttpErrors, Request} from '@loopback/rest';
-import * as samlStrategy from '@node-saml/passport-saml';
-import {
- AuthUser,
- SamlSignUpFn,
- SignUpBindings,
- UserCredentialsRepository,
- UserRepository,
-} from '@sourceloop/authentication-service';
-import {AuthErrorKeys, VerifyFunction} from 'loopback4-authentication';
-
-export class SamlVerifyProvider implements Provider {
- constructor(
- @repository(UserRepository)
- public userRepository: UserRepository,
- @repository(UserCredentialsRepository)
- public userCredsRepository: UserCredentialsRepository,
- @inject(SignUpBindings.SAML_SIGN_UP_PROVIDER)
- private readonly signupProvider: SamlSignUpFn,
- ) {}
-
- value(): VerifyFunction.SamlFn {
- return async (
- profile: samlStrategy.Profile,
- cb: samlStrategy.VerifiedCallback,
- req?: Request,
- ) => {
- const user = await this.signupProvider(profile);
- if (user == null) {
- throw new HttpErrors.Unauthorized(AuthErrorKeys.InvalidCredentials);
- }
- // Just to check if userCreds has entry for this user for this provider
- const creds = await this.userCredsRepository.findOne({
- where: {
- userId: user.id,
- authProvider: 'saml',
- },
- });
- if (
- !creds ||
- creds.authProvider !== 'saml' ||
- creds.authId !== profile.ID
- ) {
- throw new HttpErrors.Unauthorized(AuthErrorKeys.InvalidCredentials);
- }
-
- const authUser: AuthUser = new AuthUser(user);
- authUser.permissions = [];
- return authUser;
- };
- }
-}
diff --git a/sandbox/oauth-example/src/repositories/README.md b/sandbox/oauth-example/src/repositories/README.md
deleted file mode 100644
index 08638a7878..0000000000
--- a/sandbox/oauth-example/src/repositories/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Repositories
-
-This directory contains code for repositories provided by this app.
diff --git a/sandbox/oauth-example/src/repositories/index.ts b/sandbox/oauth-example/src/repositories/index.ts
deleted file mode 100644
index 01467df1a8..0000000000
--- a/sandbox/oauth-example/src/repositories/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-export * from './role.repository';
-export * from './tenant.repository';
-export * from './user.repository';
diff --git a/sandbox/oauth-example/src/repositories/role.repository.ts b/sandbox/oauth-example/src/repositories/role.repository.ts
deleted file mode 100644
index 50563bea76..0000000000
--- a/sandbox/oauth-example/src/repositories/role.repository.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {inject} from '@loopback/core';
-import {juggler} from '@loopback/repository';
-import {DefaultSoftCrudRepository} from '@sourceloop/core';
-import {AuthDbSourceName, Role} from '@sourceloop/authentication-service';
-
-export class RoleRepository extends DefaultSoftCrudRepository<
- Role,
- typeof Role.prototype.id
-> {
- constructor(
- @inject(`datasources.${AuthDbSourceName}`)
- dataSource: juggler.DataSource,
- ) {
- super(Role, dataSource);
- }
-}
diff --git a/sandbox/oauth-example/src/repositories/tenant.repository.ts b/sandbox/oauth-example/src/repositories/tenant.repository.ts
deleted file mode 100644
index 0e13056fb6..0000000000
--- a/sandbox/oauth-example/src/repositories/tenant.repository.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {Getter, inject} from '@loopback/core';
-import {
- HasManyRepositoryFactory,
- juggler,
- repository,
-} from '@loopback/repository';
-import {DefaultSoftCrudRepository} from '@sourceloop/core';
-import {
- AuthDbSourceName,
- Tenant,
- TenantConfig,
- TenantConfigRepository,
-} from '@sourceloop/authentication-service';
-
-export class TenantRepository extends DefaultSoftCrudRepository<
- Tenant,
- typeof Tenant.prototype.id
-> {
- public readonly tenantConfigs: HasManyRepositoryFactory<
- TenantConfig,
- typeof Tenant.prototype.id
- >;
-
- constructor(
- @inject(`datasources.${AuthDbSourceName}`) dataSource: juggler.DataSource,
- @repository.getter('TenantConfigRepository')
- protected tenantConfigRepositoryGetter: Getter,
- ) {
- super(Tenant, dataSource);
- this.tenantConfigs = this.createHasManyRepositoryFactoryFor(
- 'tenantConfigs',
- tenantConfigRepositoryGetter,
- );
- this.registerInclusionResolver(
- 'tenantConfigs',
- this.tenantConfigs.inclusionResolver,
- );
- }
-}
diff --git a/sandbox/oauth-example/src/repositories/user.repository.ts b/sandbox/oauth-example/src/repositories/user.repository.ts
deleted file mode 100644
index edb6c28e41..0000000000
--- a/sandbox/oauth-example/src/repositories/user.repository.ts
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {Getter, inject} from '@loopback/core';
-import {
- BelongsToAccessor,
- DataObject,
- HasManyRepositoryFactory,
- HasOneRepositoryFactory,
- Options,
- juggler,
- repository,
-} from '@loopback/repository';
-import {HttpErrors} from '@loopback/rest';
-import {
- AuthDbSourceName,
- OtpRepository,
- Tenant,
- TenantRepository,
- User,
- UserCredentials,
- UserCredentialsRepository,
- UserRelations,
- UserTenant,
- UserTenantRepository,
-} from '@sourceloop/authentication-service';
-import {
- AuthProvider,
- AuthenticateErrorKeys,
- DefaultSoftCrudRepository,
- ILogger,
- LOGGER,
- UserStatus,
-} from '@sourceloop/core';
-import * as bcrypt from 'bcrypt';
-import {AuthErrorKeys} from 'loopback4-authentication';
-
-const saltRounds = 10;
-
-export class UserRepository extends DefaultSoftCrudRepository<
- User,
- typeof User.prototype.id,
- UserRelations
-> {
- public readonly credentials: HasOneRepositoryFactory<
- UserCredentials,
- typeof User.prototype.id
- >;
- public readonly tenant: BelongsToAccessor;
-
- public readonly userTenants: HasManyRepositoryFactory<
- UserTenant,
- typeof User.prototype.id
- >;
-
- constructor(
- @inject(`datasources.${AuthDbSourceName}`)
- dataSource: juggler.DataSource,
- @repository.getter(UserCredentialsRepository)
- getUserCredsRepository: Getter,
- @repository.getter(OtpRepository)
- public getOtpRepository: Getter,
- @repository.getter('TenantRepository')
- protected tenantRepositoryGetter: Getter,
- @repository.getter('UserTenantRepository')
- protected userTenantRepositoryGetter: Getter,
- @inject(LOGGER.LOGGER_INJECT) private readonly logger: ILogger,
- ) {
- super(User, dataSource);
- this.userTenants = this.createHasManyRepositoryFactoryFor(
- 'userTenants',
- userTenantRepositoryGetter,
- );
- this.registerInclusionResolver(
- 'userTenants',
- this.userTenants.inclusionResolver,
- );
- this.tenant = this.createBelongsToAccessorFor(
- 'defaultTenant',
- tenantRepositoryGetter,
- );
- this.registerInclusionResolver(
- 'defaultTenant',
- this.tenant.inclusionResolver,
- );
-
- this.credentials = this.createHasOneRepositoryFactoryFor(
- 'credentials',
- getUserCredsRepository,
- );
- this.registerInclusionResolver(
- 'credentials',
- this.credentials.inclusionResolver,
- );
- }
-
- async create(entity: DataObject, options?: Options): Promise {
- const user = await super.create(entity, options);
- try {
- // Add temporary password for first time
- const password = (await bcrypt.hash(
- process.env.USER_TEMP_PASSWORD as string,
- saltRounds,
- )) as string;
- const creds = new UserCredentials({
- authProvider: 'internal',
- password,
- });
- await this.credentials(user.id).create(creds);
- } catch (err) {
- throw new HttpErrors.UnprocessableEntity('Error while hashing password');
- }
- return user;
- }
-
- async createWithoutPassword(
- entity: DataObject,
- options?: Options,
- ): Promise {
- return super.create(entity, options);
- }
-
- async verifyPassword(username: string, password: string): Promise {
- const user = await super.findOne({
- where: {username: username.toLowerCase()},
- });
- const creds = user && (await this.credentials(user.id).get());
- if (!user || user.deleted) {
- throw new HttpErrors.Unauthorized(AuthenticateErrorKeys.UserDoesNotExist);
- } else if (
- !creds?.password ||
- creds.authProvider !== AuthProvider.INTERNAL ||
- !(await bcrypt.compare(password, creds.password))
- ) {
- this.logger.error('User creds not found in DB or is invalid');
- throw new HttpErrors.Unauthorized(AuthErrorKeys.InvalidCredentials);
- } else {
- return user;
- }
- }
-
- async updatePassword(
- username: string,
- password: string,
- newPassword: string,
- ): Promise {
- const user = await super.findOne({where: {username}});
- const creds = user && (await this.credentials(user.id).get());
- // eslint-disable-next-line
- if (!user || user.deleted || !creds?.password) {
- throw new HttpErrors.Unauthorized(AuthenticateErrorKeys.UserDoesNotExist);
- } else if (creds.authProvider !== AuthProvider.INTERNAL) {
- throw new HttpErrors.BadRequest(
- AuthenticateErrorKeys.PasswordCannotBeChanged,
- );
- } else if (!(await bcrypt.compare(password, creds.password))) {
- throw new HttpErrors.Unauthorized(AuthErrorKeys.WrongPassword);
- } else if (await bcrypt.compare(newPassword, creds.password)) {
- throw new HttpErrors.Unauthorized(
- 'Password cannot be same as previous password!',
- );
- } else {
- // Do nothing
- }
- await this.credentials(user.id).patch({
- password: await bcrypt.hash(newPassword, saltRounds),
- });
- return user;
- }
-
- async changePassword(
- username: string,
- newPassword: string,
- oldPassword?: string,
- ): Promise {
- const user = await super.findOne({where: {username}});
- const creds = user && (await this.credentials(user.id).get());
-
- if (oldPassword) {
- // This method considers old password as OTP
- const otp = await (await this.getOtpRepository()).get(username);
- if (!otp || otp.otp !== oldPassword) {
- throw new HttpErrors.Unauthorized(AuthErrorKeys.WrongPassword);
- }
- }
-
- if (creds?.authProvider !== AuthProvider.INTERNAL) {
- throw new HttpErrors.Unauthorized(
- AuthenticateErrorKeys.PasswordCannotBeChanged,
- );
- }
- // eslint-disable-next-line
- if (!user || user.deleted || !creds?.password) {
- throw new HttpErrors.Unauthorized(AuthenticateErrorKeys.UserDoesNotExist);
- } else if (await bcrypt.compare(newPassword, creds.password)) {
- throw new HttpErrors.Unauthorized(
- 'Password cannot be same as previous password!',
- );
- } else {
- // DO nothing
- }
- await this.credentials(user.id).patch({
- password: await bcrypt.hash(newPassword, saltRounds),
- });
- return user;
- }
-
- async updateLastLogin(userId: string): Promise {
- await super.updateById(
- userId,
- {
- lastLogin: Date.now(),
- },
- {
- currentUser: {id: userId},
- },
- );
- }
-
- async firstTimeUser(userId: string): Promise {
- const user = await super.findOne({
- where: {
- id: userId,
- },
- });
-
- if (!user) {
- throw new HttpErrors.NotFound(AuthenticateErrorKeys.UserDoesNotExist);
- }
-
- const userTenant = await (
- await this.userTenantRepositoryGetter()
- ).findOne({
- where: {
- userId,
- tenantId: user.defaultTenantId,
- status: {
- inq: [UserStatus.REGISTERED, UserStatus.PASSWORD_CHANGE_NEEDED],
- },
- },
- });
- return !!userTenant;
- }
-}
diff --git a/sandbox/oauth-example/src/sequence.ts b/sandbox/oauth-example/src/sequence.ts
deleted file mode 100644
index b97f09e3c0..0000000000
--- a/sandbox/oauth-example/src/sequence.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2023 Sourcefuse Technologies
-//
-// This software is released under the MIT License.
-// https://opensource.org/licenses/MIT
-import {MiddlewareSequence} from '@loopback/rest';
-
-export class MySequence extends MiddlewareSequence {}
diff --git a/sandbox/oauth-example/tsconfig.json b/sandbox/oauth-example/tsconfig.json
index c7b8e49eac..4d768146e7 100644
--- a/sandbox/oauth-example/tsconfig.json
+++ b/sandbox/oauth-example/tsconfig.json
@@ -1,9 +1,14 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"extends": "@loopback/build/config/tsconfig.common.json",
+ "experimentalDecorators": true,
"compilerOptions": {
"outDir": "dist",
- "rootDir": "src"
+ "rootDir": "src",
+ "composite": true
},
- "include": ["src"]
-}
+ "include": [
+ "src"
+ ],
+ "references": []
+}
\ No newline at end of file
diff --git a/services/payment-service/openapi.json b/services/payment-service/openapi.json
index 778b1dc570..283e7d5473 100644
--- a/services/payment-service/openapi.json
+++ b/services/payment-service/openapi.json
@@ -2,7 +2,7 @@
"openapi": "3.0.0",
"info": {
"title": "@sourceloop/payment-service",
- "version": "14.2.0",
+ "version": "15.0.2",
"description": "payment microservice",
"contact": {
"name": "Sourcefuse"
diff --git a/services/payment-service/openapi.md b/services/payment-service/openapi.md
index 292f1d864f..272ee2b198 100644
--- a/services/payment-service/openapi.md
+++ b/services/payment-service/openapi.md
@@ -1,5 +1,5 @@
---
-title: "@sourceloop/payment-service v14.2.0"
+title: "@sourceloop/payment-service v15.0.2"
language_tabs:
- javascript: JavaScript
- javascript--nodejs: Node.JS
@@ -16,7 +16,7 @@ headingLevel: 2
-@sourceloop/payment-service v14.2.0
+@sourceloop/payment-service v15.0.2
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
diff --git a/services/reporting-service/openapi.json b/services/reporting-service/openapi.json
index b89fcc3a4c..d61d1e8bb1 100644
--- a/services/reporting-service/openapi.json
+++ b/services/reporting-service/openapi.json
@@ -2,7 +2,7 @@
"openapi": "3.0.0",
"info": {
"title": "@sourceloop/reporting-service",
- "version": "3.1.0",
+ "version": "4.0.2",
"description": "reporting-service.",
"contact": {
"name": "Sourav Bhargava",
diff --git a/services/reporting-service/openapi.md b/services/reporting-service/openapi.md
index 590413270a..0b1074df83 100644
--- a/services/reporting-service/openapi.md
+++ b/services/reporting-service/openapi.md
@@ -1,5 +1,5 @@
---
-title: "@sourceloop/reporting-service v3.1.0"
+title: "@sourceloop/reporting-service v4.0.2"
language_tabs:
- javascript: JavaScript
- javascript--nodejs: Node.JS
@@ -16,7 +16,7 @@ headingLevel: 2
-@sourceloop/reporting-service v3.1.0
+@sourceloop/reporting-service v4.0.2
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
diff --git a/services/user-tenant-service/openapi.json b/services/user-tenant-service/openapi.json
index 54af6ca2af..8c71e9f2a5 100644
--- a/services/user-tenant-service/openapi.json
+++ b/services/user-tenant-service/openapi.json
@@ -2,7 +2,7 @@
"openapi": "3.0.0",
"info": {
"title": "@sourceloop/user-tenant-service",
- "version": "2.3.0",
+ "version": "3.0.2",
"description": "Sourceloop User Tenant Service",
"contact": {
"name": "SourceFuse"
diff --git a/services/user-tenant-service/openapi.md b/services/user-tenant-service/openapi.md
index 12abbf13c2..1d34d3b0cc 100644
--- a/services/user-tenant-service/openapi.md
+++ b/services/user-tenant-service/openapi.md
@@ -1,5 +1,5 @@
---
-title: "@sourceloop/user-tenant-service v2.3.0"
+title: "@sourceloop/user-tenant-service v3.0.2"
language_tabs:
- javascript: JavaScript
- javascript--nodejs: Node.JS
@@ -16,7 +16,7 @@ headingLevel: 2
-@sourceloop/user-tenant-service v2.3.0
+@sourceloop/user-tenant-service v3.0.2
> Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.