Browse Source

WIP - Auth0 implementation

new_auth
Dan 2 years ago
parent
commit
16e177e220
  1. 199
      package-lock.json
  2. 2
      packages/bridge-server/.env
  3. 21
      packages/bridge-server/.vscode/launch.json
  4. 5
      packages/bridge-server/package.json
  5. 2
      packages/bridge-server/src/app.module.ts
  6. 22
      packages/bridge-server/src/authz/authz.controller.ts
  7. 26
      packages/bridge-server/src/authz/authz.guard.ts
  8. 12
      packages/bridge-server/src/authz/authz.module.ts
  9. 33
      packages/bridge-server/src/authz/jwt.strategy.ts
  10. 1
      packages/bridge-ui/package.json
  11. 27
      packages/bridge-ui/src/app/app.config.ts
  12. 2
      packages/bridge-ui/src/app/components/login-dialog/login-dialog.component.ts
  13. 9
      packages/bridge-ui/src/app/components/top-bar/top-bar.component.html
  14. 11
      packages/bridge-ui/src/app/components/top-bar/top-bar.component.ts
  15. 40
      packages/bridge-ui/src/app/services/auth.service.ts

199
package-lock.json

@ -1589,6 +1589,25 @@
"integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
"dev": true
},
"node_modules/@auth0/auth0-angular": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@auth0/auth0-angular/-/auth0-angular-2.2.1.tgz",
"integrity": "sha512-ie9CMNOdQ3mkhhe09SEporCayDuuPYHNmctyHeV6caVgZVSSu9FlFt2ec6CkX27ufDq7yCdyJGnDixWxNtUG+Q==",
"dependencies": {
"@auth0/auth0-spa-js": "^2.0.1",
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": ">=13",
"@angular/core": ">=13",
"@angular/router": ">=13"
}
},
"node_modules/@auth0/auth0-spa-js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-2.1.2.tgz",
"integrity": "sha512-xdA65Z/U7++Y7L9Uwh8Q8OVOs6qgFz+fb7GAzHFjpr1icO37B//xdzLXm7ZRgA19RWrsNe1nme3h896igJSvvw=="
},
"node_modules/@babel/code-frame": {
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
@ -5881,6 +5900,15 @@
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0"
}
},
"node_modules/@nestjs/passport": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.2.tgz",
"integrity": "sha512-od31vfB2z3y05IDB5dWSbCGE2+pAf2k2WCBinNuTTOxN0O0+wtO1L3kawj/aCW3YR9uxsTOVbTDwtwgpNNsnjQ==",
"peerDependencies": {
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
"passport": "^0.4.0 || ^0.5.0 || ^0.6.0"
}
},
"node_modules/@nestjs/platform-express": {
"version": "10.2.9",
"resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.2.9.tgz",
@ -7250,7 +7278,6 @@
"version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
"dev": true,
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
@ -7269,7 +7296,6 @@
"version": "3.4.38",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
@ -7352,7 +7378,6 @@
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
"dev": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.33",
@ -7364,7 +7389,6 @@
"version": "4.17.41",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
"integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
"dev": true,
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
@ -7384,8 +7408,7 @@
"node_modules/@types/http-errors": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
"dev": true
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="
},
"node_modules/@types/http-proxy": {
"version": "1.17.14",
@ -7459,8 +7482,7 @@
"node_modules/@types/mime": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"dev": true
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
},
"node_modules/@types/minimatch": {
"version": "3.0.5",
@ -7511,17 +7533,45 @@
"integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
"dev": true
},
"node_modules/@types/passport": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz",
"integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==",
"dev": true,
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/passport-jwt": {
"version": "3.0.13",
"resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-3.0.13.tgz",
"integrity": "sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==",
"dev": true,
"dependencies": {
"@types/express": "*",
"@types/jsonwebtoken": "*",
"@types/passport-strategy": "*"
}
},
"node_modules/@types/passport-strategy": {
"version": "0.2.38",
"resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz",
"integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==",
"dev": true,
"dependencies": {
"@types/express": "*",
"@types/passport": "*"
}
},
"node_modules/@types/qs": {
"version": "6.9.10",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz",
"integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==",
"dev": true
"integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw=="
},
"node_modules/@types/range-parser": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"dev": true
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="
},
"node_modules/@types/retry": {
"version": "0.12.0",
@ -7539,7 +7589,6 @@
"version": "0.17.4",
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
"dev": true,
"dependencies": {
"@types/mime": "^1",
"@types/node": "*"
@ -7570,7 +7619,6 @@
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
"integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
"dev": true,
"dependencies": {
"@types/http-errors": "*",
"@types/mime": "*",
@ -14775,6 +14823,14 @@
"jiti": "bin/jiti.js"
}
},
"node_modules/jose": {
"version": "4.15.4",
"resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz",
"integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/js-beautify": {
"version": "1.14.11",
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz",
@ -15018,6 +15074,22 @@
"safe-buffer": "^5.0.1"
}
},
"node_modules/jwks-rsa": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.1.0.tgz",
"integrity": "sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==",
"dependencies": {
"@types/express": "^4.17.17",
"@types/jsonwebtoken": "^9.0.2",
"debug": "^4.3.4",
"jose": "^4.14.6",
"limiter": "^1.1.5",
"lru-memoizer": "^2.2.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
@ -15669,8 +15741,7 @@
"node_modules/limiter": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
"integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==",
"dev": true
"integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
},
"node_modules/lines-and-columns": {
"version": "2.0.4",
@ -15830,6 +15901,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@ -15938,6 +16014,29 @@
"node": ">=10"
}
},
"node_modules/lru-memoizer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz",
"integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==",
"dependencies": {
"lodash.clonedeep": "^4.5.0",
"lru-cache": "~4.0.0"
}
},
"node_modules/lru-memoizer/node_modules/lru-cache": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz",
"integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==",
"dependencies": {
"pseudomap": "^1.0.1",
"yallist": "^2.0.0"
}
},
"node_modules/lru-memoizer/node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
},
"node_modules/lru-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
@ -18235,6 +18334,41 @@
"node": ">= 0.8"
}
},
"node_modules/passport": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
"integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
"peer": true,
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1",
"utils-merge": "^1.0.1"
},
"engines": {
"node": ">= 0.4.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
}
},
"node_modules/passport-jwt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz",
"integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==",
"dependencies": {
"jsonwebtoken": "^9.0.0",
"passport-strategy": "^1.0.0"
}
},
"node_modules/passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@ -18313,6 +18447,11 @@
"node": ">=8"
}
},
"node_modules/pause": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
},
"node_modules/pg-connection-string": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
@ -18719,6 +18858,11 @@
"dev": true,
"optional": true
},
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ=="
},
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@ -23764,9 +23908,13 @@
"@nestjs/core": "^10.0.0",
"@nestjs/event-emitter": "^2.0.3",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.2",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/sequelize": "^10.0.0",
"bridge-shared": "^1.0.0",
"jwks-rsa": "^3.1.0",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"sequelize": "^6.35.1",
@ -23783,6 +23931,7 @@
"@types/jest": "^29.5.2",
"@types/multer": "^1.4.11",
"@types/node": "^20.3.1",
"@types/passport-jwt": "^3.0.13",
"@types/sequelize": "^4.28.18",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^6.0.0",
@ -23801,6 +23950,23 @@
"typescript": "^5.1.3"
}
},
"packages/bridge-server/node_modules/passport": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
"integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1",
"utils-merge": "^1.0.1"
},
"engines": {
"node": ">= 0.4.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
}
},
"packages/bridge-shared": {
"version": "1.0.0",
"license": "ISC",
@ -23836,6 +24002,7 @@
"@angular/platform-browser": "^17.0.0",
"@angular/platform-browser-dynamic": "^17.0.0",
"@angular/router": "^17.0.0",
"@auth0/auth0-angular": "^2.2.1",
"bridge-shared": "^1.0.0",
"eventemitter3": "^5.0.1",
"jwt-decode": "^4.0.0",

2
packages/bridge-server/.env

@ -0,0 +1,2 @@
AUTH0_ISSUER_URL=https://dev-0pjms7kv5foqe0ex.uk.auth0.com/
AUTH0_AUDIENCE=https://ponyta.pkmn.cloud

21
packages/bridge-server/.vscode/launch.json

@ -0,0 +1,21 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\src\\authz\\authz.guard.ts",
"preLaunchTask": "tsc: build - tsconfig.json",
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
}
]
}

5
packages/bridge-server/package.json

@ -24,9 +24,13 @@
"@nestjs/core": "^10.0.0",
"@nestjs/event-emitter": "^2.0.3",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.2",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/sequelize": "^10.0.0",
"bridge-shared": "^1.0.0",
"jwks-rsa": "^3.1.0",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"sequelize": "^6.35.1",
@ -43,6 +47,7 @@
"@types/jest": "^29.5.2",
"@types/multer": "^1.4.11",
"@types/node": "^20.3.1",
"@types/passport-jwt": "^3.0.13",
"@types/sequelize": "^4.28.18",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^6.0.0",

2
packages/bridge-server/src/app.module.ts

@ -25,6 +25,7 @@ import { SeasonStandingsModule } from './season-standings/season-standings.modul
import { UploadModule } from './upload/upload.module';
import { SseService } from './sse/sse.service';
import { SseModule } from './sse/sse.module';
import { AuthzModule } from './authz/authz.module';
@Module({
imports: [
@ -62,6 +63,7 @@ import { SseModule } from './sse/sse.module';
SeasonStandingsModule,
UploadModule,
SseModule,
AuthzModule,
],
controllers: [AppController, SeasonsController, UploadController],
providers: [AppService, UsersService, RacersService, RacesService, SeasonStandingsService, RaceResultsService, SseService],

22
packages/bridge-server/src/authz/authz.controller.ts

@ -0,0 +1,22 @@
import {
Body,
Controller,
Get,
HttpCode,
HttpStatus,
Post,
Request,
UseGuards
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Controller('authz')
export class AuthzController {
constructor() {}
@UseGuards(AuthGuard('jwt'))
@Get('test')
getProfile(@Request() req) {
return "Hello";
}
}

26
packages/bridge-server/src/authz/authz.guard.ts

@ -0,0 +1,26 @@
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
console.log("runnign")
// Add your custom authentication logic here
// for example, call super.logIn(request) to establish a session.
return super.canActivate(context);
}
handleRequest(err, user, info) {
console.log("runnign!!")
// You can throw an exception based on either "info" or "err" arguments
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}

12
packages/bridge-server/src/authz/authz.module.ts

@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { AuthzController } from './authz.controller';
@Module({
imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
providers: [JwtStrategy],
controllers: [AuthzController],
exports: [PassportModule],
})
export class AuthzModule {}

33
packages/bridge-server/src/authz/jwt.strategy.ts

@ -0,0 +1,33 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { passportJwtSecret } from 'jwks-rsa';
import * as dotenv from 'dotenv';
dotenv.config();
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `${process.env.AUTH0_ISSUER_URL}.well-known/jwks.json`,
}),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
audience: process.env.AUTH0_AUDIENCE,
issuer: `${process.env.AUTH0_ISSUER_URL}`,
algorithms: ['RS256'],
});
}
validate(payload: unknown): unknown {
console.log(payload)
return payload;
}
}

1
packages/bridge-ui/package.json

@ -20,6 +20,7 @@
"@angular/platform-browser": "^17.0.0",
"@angular/platform-browser-dynamic": "^17.0.0",
"@angular/router": "^17.0.0",
"@auth0/auth0-angular": "^2.2.1",
"bridge-shared": "^1.0.0",
"eventemitter3": "^5.0.1",
"jwt-decode": "^4.0.0",

27
packages/bridge-ui/src/app/app.config.ts

@ -7,6 +7,7 @@ import { provideAnimations } from '@angular/platform-browser/animations';
import { routes } from './app.routes';
import { AuthInterceptor } from './interceptors/auth.interceptor';
import { SnackbarInterceptor } from './interceptors/snackbar.interceptor';
import { AuthHttpInterceptor, AuthModule } from '@auth0/auth0-angular';
export const appConfig: ApplicationConfig = {
providers: [
@ -16,7 +17,31 @@ export const appConfig: ApplicationConfig = {
withInterceptorsFromDi()
),
importProvidersFrom(MatNativeDateModule),
{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: SnackbarInterceptor, multi: true},
importProvidersFrom(AuthModule.forRoot({
domain: 'dev-0pjms7kv5foqe0ex.uk.auth0.com',
clientId: 'GZFNgt0sFgBZFbj5uBK5s1cRZELYUstm',
authorizationParams: {
redirect_uri: window.location.origin,
audience: 'https://ponyta.pkmn.cloud'
},
httpInterceptor: {
allowedList: [
{
// Match any request that starts 'https://{yourDomain}/api/v2/' (note the asterisk)
//uri: 'https://ponyta.pkmn.cloud/*',
uri: 'http://localhost:3000/*',
tokenOptions: {
authorizationParams: {
// The attached token should target this audience
audience: 'https://ponyta.pkmn.cloud'
}
}
}
]
}
}))
]
};

2
packages/bridge-ui/src/app/components/login-dialog/login-dialog.component.ts

@ -49,6 +49,7 @@ export class LoginDialogComponent {
let username = this.username.value != undefined ? this.username.value : "";
let password = this.password.value != undefined ? this.password.value : "";
/*
this.authService.login(username, password).subscribe(data => {
console.log(data)
if (data.access_token) {
@ -56,5 +57,6 @@ export class LoginDialogComponent {
window.location.reload();
}
})
*/
}
}

9
packages/bridge-ui/src/app/components/top-bar/top-bar.component.html

@ -12,13 +12,16 @@
[options] = "options"
(themeChange)="themeChangeHandler($event)">
</app-theme-menu>
@if(isAuthed() == false) {
<button mat-icon-button class="example-icon" aria-label="Example icon-button with share icon" (click)="onProfile()">
<mat-icon>person_pin</mat-icon>
</button>
@if(isAuthenticated == false) {
<button mat-icon-button class="example-icon" aria-label="Example icon-button with share icon" (click)="onLoginClick()">
<mat-icon>login</mat-icon>
</button>
}
@if(isAuthed()) {
<button mat-icon-button class="example-icon" aria-label="Example icon-button with share icon" (click)="onProfile()">
@else {
<button mat-icon-button class="example-icon" aria-label="Example icon-button with share icon" (click)="onLogoutClick()">
<mat-icon>person_pin</mat-icon>
</button>
}

11
packages/bridge-ui/src/app/components/top-bar/top-bar.component.ts

@ -16,6 +16,8 @@ import { ThemeOption } from '../../models/theme-option.model';
import { LoginDialogComponent } from '../login-dialog/login-dialog.component';
import { AuthService } from '../../services/auth.service';
//import { AuthService } from '@auth0/auth0-angular';
@Component({
selector: 'app-top-bar',
standalone: true,
@ -34,11 +36,12 @@ import { AuthService } from '../../services/auth.service';
export class TopBarComponent {
constructor(
private readonly themeService: ThemeService,
private authService: AuthService,
public authService: AuthService,
public dialog: MatDialog
) {}
options: Array<ThemeOption> = [];
isAuthenticated: boolean = false;
async ngOnInit() {
this.themeService.getThemeOptions().subscribe(data => {
@ -51,7 +54,11 @@ export class TopBarComponent {
}
onLoginClick() {
this.dialog.open(LoginDialogComponent);
this.authService.login();
}
onLogoutClick() {
this.authService.logout();
}
isAuthed() {

40
packages/bridge-ui/src/app/services/auth.service.ts

@ -4,33 +4,57 @@ import { Observable } from 'rxjs';
import { jwtDecode } from "jwt-decode";
import { ServerEndpointService } from './server-endpoint.service';
import { AuthService as Auth0Service } from '@auth0/auth0-angular';
@Injectable({
providedIn: 'root'
})
export class AuthService {
_isAuthenticated:boolean = false;
constructor(
private httpClient: HttpClient,
private serverEndpointService: ServerEndpointService,
) { }
private auth0: Auth0Service
)
{
localStorage.removeItem('token');
login(username: string, password: string): Observable<any> {
const headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
return this.httpClient.post(this.serverEndpointService.getCurrentEndpoint()+"auth/login", { username, password }, { headers })
this.auth0.isAuthenticated$.subscribe(authed => {
this._isAuthenticated = authed;
});
this.auth0.user$.subscribe(user => {
console.log(user);
})
this.auth0.idTokenClaims$.subscribe(data => {
console.log(data)
if (data && data.__raw) {
localStorage.setItem('token', data.__raw);
}
})
}
login() {
this.auth0.loginWithRedirect();
}
testProfile(): Observable<any> {
console.log("SendTestProfile")
return this.httpClient.get(this.serverEndpointService.getCurrentEndpoint()+"auth/profile")
return this.httpClient.get(this.serverEndpointService.getCurrentEndpoint()+"authz/test")
}
logout(): void {
// Clear the token from local storage
this.auth0.logout();
localStorage.removeItem('token');
}
isAuthenticated(): boolean {
if(!this._isAuthenticated) {
return false;
}
const token = localStorage.getItem('token');
if (!token) {

Loading…
Cancel
Save