From 2fbc789724143287a9c0f41418834e6ab34a6eeb Mon Sep 17 00:00:00 2001 From: lumijiez <59575049+lumijiez@users.noreply.github.com> Date: Wed, 4 Jun 2025 16:09:53 +0300 Subject: [PATCH] Implement Auth0, + templates. --- docker-compose.yml | 34 +- nginx/nginx.conf | 28 +- src/Imprink.WebApi/Imprink.WebApi.csproj | 1 + src/Imprink.WebApi/Startup.cs | 16 + webui/auth0-templates/login.html | 759 +++++++++++++++++++++++ webui/package-lock.json | 86 +++ webui/package.json | 5 +- webui/src/app/page.js | 96 +-- webui/src/lib/auth0.js | 8 + webui/src/middleware.js | 11 + 10 files changed, 943 insertions(+), 101 deletions(-) create mode 100644 webui/auth0-templates/login.html create mode 100644 webui/src/lib/auth0.js create mode 100644 webui/src/middleware.js diff --git a/docker-compose.yml b/docker-compose.yml index 1436842..e87110c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,14 @@ services: - "80" environment: - ASPNETCORE_ENVIRONMENT=Development - - ConnectionStrings__DefaultConnection=Server=sqlserver;Database=Printbase;User Id=sa;Password=YourStrong(!)Password;Encrypt=false;TrustServerCertificate=true;MultipleActiveResultSets=true; + - ConnectionStrings__DefaultConnection=Server=${SQL_SERVER};Database=${SQL_DATABASE};User Id=${SQL_USER_ID};Password=${SQL_PASSWORD};Encrypt=false;TrustServerCertificate=true;MultipleActiveResultSets=true; + - ASPNETCORE_URLS=http://+:8080 + - Auth0__Domain=${AUTH0_ISSUER_BASE_URL} + - Auth0__Audience=${AUTH0_AUDIENCE} depends_on: - mssql + networks: + - app-network webui: image: node:18-alpine @@ -20,7 +25,19 @@ services: - "3000" environment: - NODE_ENV=development + - AUTH0_SECRET=${AUTH0_SECRET} + - APP_BASE_URL=${APP_BASE_URL} + - AUTH0_DOMAIN=${AUTH0_ISSUER_BASE_URL} + - AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID} + - AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET} + - AUTH0_AUDIENCE=${AUTH0_AUDIENCE} + - AUTH0_SCOPE=openid profile email read:shows + - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} + - NEXT_PUBLIC_AUTH0_CLIENT_ID=${NEXT_PUBLIC_AUTH0_CLIENT_ID} + - NEXT_PUBLIC_AUTH0_DOMAIN=${NEXT_PUBLIC_AUTH0_DOMAIN} command: "sh -c 'npm install && npm run dev'" + networks: + - app-network mssql: image: mcr.microsoft.com/mssql/server:2022-latest @@ -28,16 +45,27 @@ services: ports: - "1433:1433" environment: - SA_PASSWORD: "YourStrong(!)Password" + SA_PASSWORD: "${SQL_PASSWORD}" ACCEPT_EULA: "Y" restart: unless-stopped + networks: + - app-network nginx: image: nginx:latest ports: - "80:80" + - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./ssl/impr.ink-chain.pem:/etc/ssl/certs/impr.ink.crt:ro + - ./ssl/impr.ink-key.pem:/etc/ssl/private/impr.ink.key:ro depends_on: - webapi - - webui \ No newline at end of file + - webui + networks: + - app-network + +networks: + app-network: + driver: bridge \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 2b23d29..19fb768 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -1,6 +1,14 @@ -events {} +events { + worker_connections 1024; +} http { + proxy_buffer_size 16k; + proxy_buffers 4 16k; + proxy_busy_buffers_size 16k; + + large_client_header_buffers 4 16k; + upstream webapi { server webapi:8080; } @@ -11,6 +19,24 @@ http { server { listen 80; + server_name impr.ink; + return 301 https://$server_name$request_uri; + } + + server { + listen 443 ssl http2; + server_name impr.ink; + + ssl_certificate /etc/ssl/certs/impr.ink.crt; + ssl_certificate_key /etc/ssl/private/impr.ink.key; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; location /api/ { proxy_pass http://webapi/; diff --git a/src/Imprink.WebApi/Imprink.WebApi.csproj b/src/Imprink.WebApi/Imprink.WebApi.csproj index 714d412..62a158e 100644 --- a/src/Imprink.WebApi/Imprink.WebApi.csproj +++ b/src/Imprink.WebApi/Imprink.WebApi.csproj @@ -9,6 +9,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Imprink.WebApi/Startup.cs b/src/Imprink.WebApi/Startup.cs index b3ed443..42fe7a3 100644 --- a/src/Imprink.WebApi/Startup.cs +++ b/src/Imprink.WebApi/Startup.cs @@ -1,10 +1,13 @@ +using System.Security.Claims; using Imprink.Application; using Imprink.Application.Products.Handlers; using Imprink.Domain.Repositories; using Imprink.Infrastructure; using Imprink.Infrastructure.Database; using Imprink.Infrastructure.Repositories; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; namespace Imprink.WebApi; @@ -28,6 +31,19 @@ public static class Startup { cfg.RegisterServicesFromAssembly(typeof(CreateProductHandler).Assembly); }); + + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = $"https://{builder.Configuration["Auth0:Domain"]}/"; + options.Audience = builder.Configuration["Auth0:Audience"]; + options.TokenValidationParameters = new TokenValidationParameters + { + NameClaimType = ClaimTypes.NameIdentifier + }; + }); + + builder.Services.AddAuthorization(); services.AddControllers(); services.AddSwaggerGen(); diff --git a/webui/auth0-templates/login.html b/webui/auth0-templates/login.html new file mode 100644 index 0000000..aab1df5 --- /dev/null +++ b/webui/auth0-templates/login.html @@ -0,0 +1,759 @@ + + + + + + + Sign In | Imprink + + + + + + + + + + + + + + + + + diff --git a/webui/package-lock.json b/webui/package-lock.json index 042691f..5dfcd57 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -8,6 +8,7 @@ "name": "webui", "version": "0.1.0", "dependencies": { + "@auth0/nextjs-auth0": "^4.6.0", "next": "15.3.3", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -44,6 +45,33 @@ "node": ">=6.0.0" } }, + "node_modules/@auth0/nextjs-auth0": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@auth0/nextjs-auth0/-/nextjs-auth0-4.6.0.tgz", + "integrity": "sha512-HK+fcUW6P8/qUDQfOfntftMg6yzeZLtyfTxL/lyeOub1o/xTL9SZ2fF39nH0H6w1loB5SCAbyN1vD8xxBwINqQ==", + "license": "MIT", + "dependencies": { + "@edge-runtime/cookies": "^5.0.1", + "@panva/hkdf": "^1.2.1", + "jose": "^5.9.6", + "oauth4webapi": "^3.1.2", + "swr": "^2.2.5" + }, + "peerDependencies": { + "next": "^14.2.25 || ^15.2.3", + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + } + }, + "node_modules/@edge-runtime/cookies": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/cookies/-/cookies-5.0.2.tgz", + "integrity": "sha512-Sd8LcWpZk/SWEeKGE8LT6gMm5MGfX/wm+GPnh1eBEtCpya3vYqn37wYknwAHw92ONoyyREl1hJwxV/Qx2DWNOg==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/@emnapi/runtime": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", @@ -650,6 +678,15 @@ "node": ">= 10" } }, + "node_modules/@panva/hkdf": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", + "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -1033,6 +1070,15 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", @@ -1081,6 +1127,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/lightningcss": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", @@ -1469,6 +1524,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/oauth4webapi": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.1.tgz", + "integrity": "sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1636,6 +1700,19 @@ } } }, + "node_modules/swr": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz", + "integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/tailwindcss": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.8.tgz", @@ -1677,6 +1754,15 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/webui/package.json b/webui/package.json index 546eba8..eaf30ad 100644 --- a/webui/package.json +++ b/webui/package.json @@ -9,9 +9,10 @@ "lint": "next lint" }, "dependencies": { + "@auth0/nextjs-auth0": "^4.6.0", + "next": "15.3.3", "react": "^19.0.0", - "react-dom": "^19.0.0", - "next": "15.3.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@tailwindcss/postcss": "^4", diff --git a/webui/src/app/page.js b/webui/src/app/page.js index d625a20..af50faf 100644 --- a/webui/src/app/page.js +++ b/webui/src/app/page.js @@ -3,101 +3,7 @@ import Image from "next/image"; export default function Home() { return (
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.js - - . -
  2. -
  3. - Save and see your changes instantly. -
  4. -
- - -
- + Login
); } diff --git a/webui/src/lib/auth0.js b/webui/src/lib/auth0.js new file mode 100644 index 0000000..79fd779 --- /dev/null +++ b/webui/src/lib/auth0.js @@ -0,0 +1,8 @@ +import { Auth0Client } from "@auth0/nextjs-auth0/server"; + +export const auth0 = new Auth0Client({ + authorizationParameters: { + scope: 'openid profile email read:shows', + audience: 'imprink-front' + } +}); \ No newline at end of file diff --git a/webui/src/middleware.js b/webui/src/middleware.js new file mode 100644 index 0000000..03e6e61 --- /dev/null +++ b/webui/src/middleware.js @@ -0,0 +1,11 @@ +import { auth0 } from "./lib/auth0"; + +export async function middleware(request) { + return await auth0.middleware(request); +} + +export const config = { + matcher: [ + "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)", + ], +}; \ No newline at end of file