diff --git a/.env-sample b/.env-sample index 3c7da79..2db3554 100644 --- a/.env-sample +++ b/.env-sample @@ -1,22 +1,29 @@ -# NoteBookmark Docker Compose Environment Variables -# Copy this file to .env and replace all placeholder values with your actual configuration +# Copy to docker-compose/.env and set values. -# Keycloak Admin Credentials -KEYCLOAK_ADMIN_PASSWORD=your-secure-admin-password +# Keycloak +KEYCLOAK_USER=admin +KEYCLOAK_PASSWORD=admin -# Keycloak Client Configuration +# Keycloak host (local default). +KEYCLOAK_URL=localhost + +# Postgres for Keycloak. +POSTGRES_USER=keycloak +POSTGRES_PASSWORD=change-me + +# App auth (OIDC) KEYCLOAK_AUTHORITY=http://localhost:8080/realms/notebookmark KEYCLOAK_CLIENT_ID=notebookmark -KEYCLOAK_CLIENT_SECRET=your-keycloak-client-secret +KEYCLOAK_CLIENT_SECRET=replace-with-client-secret -# Azure Storage - Table Storage Connection -NB_STORAGE_OUTPUTS_TABLEENDPOINT=https://your-storage-account.table.core.windows.net/ +# Optional +# Keycloak__RequireHttpsMetadata=false -# Azure Storage - Blob Storage Connection +# AI +REKA_API_KEY=replace-with-reka-api-key + +# Storage +NB_STORAGE_OUTPUTS_TABLEENDPOINT=https://your-storage-account.table.core.windows.net/ NB_STORAGE_OUTPUTS_BLOBENDPOINT=https://your-storage-account.blob.core.windows.net/ -# Notes: -# - Never commit the .env file to version control -# - Keep credentials secure and rotate them regularly -# - For local development, you can use "admin" as KEYCLOAK_ADMIN_PASSWORD -# - For production, use strong passwords and proper Azure Storage connection strings +# Do not commit docker-compose/.env. diff --git a/README.md b/README.md index ca99229..b180fe8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,17 @@ NoteBookmark is composed of three main sections: ![Slide show of all NoteBookmark Screens](gh/images/NoteBookmark-Tour_hd.gif) +## Run Options + +- Development: running the Aspire project is the easiest path and everything is wired automatically. +- Production-style: run with containers and deploy to Azure. + +Run locally with Aspire: + +```bash +dotnet run --project src/NoteBookmark.AppHost +``` + ## How to deploy Your own NoteBookmark ### Get the code on your machine @@ -52,8 +63,9 @@ Voila! Your app is now secure. ## Documentation For detailed setup guides and configuration information: +- [Keycloak Container Setup](/docs/keycloak-container-setup.md) - Start a local Keycloak instance if you do not already have one - [Keycloak Authentication Setup](/docs/keycloak-setup.md) - Complete guide for setting up Keycloak authentication -- [Docker Compose Deployment](/docs/docker-compose-deployment.md) - Deploy with Docker Compose (generate from Aspire or use provided files) +- [Docker Compose Deployment](/docs/docker-compose-deployment.md) - Deploy NoteBookmark containers (assumes a healthy Keycloak + configured realm) ## Contributing diff --git a/docker-compose/build-and-push.ps1 b/docker-compose/build-and-push.ps1 deleted file mode 100644 index f0cdc83..0000000 --- a/docker-compose/build-and-push.ps1 +++ /dev/null @@ -1,52 +0,0 @@ -# Build and Push Docker Images Script -# Make sure you're logged in to Docker Hub first: docker login - -param( - [Parameter(Mandatory=$true)] - [string]$DockerHubUsername, - - [string]$ApiTag = "latest", - [string]$BlazorTag = "latest" -) - -Write-Host "Building and pushing Docker images for NoteBookmark..." -ForegroundColor Green - -# Build API image -Write-Host "Building API image..." -ForegroundColor Yellow -docker build -f ../src/NoteBookmark.Api/Dockerfile -t "$DockerHubUsername/notebookmark-api:$ApiTag" .. - -if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to build API image" - exit 1 -} - -# Build Blazor App image -Write-Host "Building Blazor App image..." -ForegroundColor Yellow -docker build -f ../src/NoteBookmark.BlazorApp/Dockerfile -t "$DockerHubUsername/notebookmark-blazor:$BlazorTag" .. - -if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to build Blazor App image" - exit 1 -} - -# Push API image -Write-Host "Pushing API image to Docker Hub..." -ForegroundColor Yellow -docker push "$DockerHubUsername/notebookmark-api:$ApiTag" - -if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to push API image" - exit 1 -} - -# Push Blazor App image -Write-Host "Pushing Blazor App image to Docker Hub..." -ForegroundColor Yellow -docker push "$DockerHubUsername/notebookmark-blazor:$BlazorTag" - -if ($LASTEXITCODE -ne 0) { - Write-Error "Failed to push Blazor App image" - exit 1 -} - -Write-Host "Successfully built and pushed both images!" -ForegroundColor Green -Write-Host "API image: $DockerHubUsername/notebookmark-api:$ApiTag" -ForegroundColor Cyan -Write-Host "Blazor image: $DockerHubUsername/notebookmark-blazor:$BlazorTag" -ForegroundColor Cyan diff --git a/docker-compose/docker-compose.yaml b/docker-compose/docker-compose.yaml deleted file mode 100644 index 3afe790..0000000 --- a/docker-compose/docker-compose.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: note-bookmark - -services: - keycloak: - image: "quay.io/keycloak/keycloak:26.1" - container_name: "notebookmark-keycloak" - command: ["start-dev"] - environment: - KEYCLOAK_ADMIN: "admin" - KEYCLOAK_ADMIN_PASSWORD: "${KEYCLOAK_ADMIN_PASSWORD:-admin}" - KC_HTTP_PORT: "8080" - KC_HOSTNAME_STRICT: "false" - KC_HOSTNAME_STRICT_HTTPS: "false" - KC_HTTP_ENABLED: "true" - ports: - - "8080:8080" - volumes: - - keycloak-data:/opt/keycloak/data - networks: - - "aspire" - api: - image: "fboucher/notebookmark-api:latest" - container_name: "notebookmark-api" - environment: - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" - ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" - HTTP_PORTS: "8000" - ConnectionStrings__nb-tables: "${NB_STORAGE_OUTPUTS_TABLEENDPOINT}" - ConnectionStrings__nb-blobs: "${NB_STORAGE_OUTPUTS_BLOBENDPOINT}" - ports: - - "8001:8000" - - "8003:8002" - networks: - - "aspire" - blazor-app: - image: "fboucher/notebookmark-blazor:latest" - container_name: "notebookmark-blazor" - environment: - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true" - OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" - ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" - HTTP_PORTS: "8004" - services__api__http__0: "http://api:8000" - services__keycloak__http__0: "http://keycloak:8080" - Keycloak__Authority: "${KEYCLOAK_AUTHORITY:-http://keycloak:8080/realms/notebookmark}" - Keycloak__ClientId: "${KEYCLOAK_CLIENT_ID:-notebookmark}" - Keycloak__ClientSecret: "${KEYCLOAK_CLIENT_SECRET}" - ports: - - "8005:8004" - - "8007:8006" - depends_on: - api: - condition: "service_started" - keycloak: - condition: "service_started" - networks: - - "aspire" -volumes: - keycloak-data: - driver: "local" -networks: - aspire: - driver: "bridge" diff --git a/docker-compose/keycloak-compose.yaml b/docker-compose/keycloak-compose.yaml new file mode 100644 index 0000000..a18921f --- /dev/null +++ b/docker-compose/keycloak-compose.yaml @@ -0,0 +1,51 @@ +name: notebookmark-keycloak + +services: + keycloak_postgres: + container_name: keycloak-postgres + image: postgres:14.18 + restart: unless-stopped + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres-data:/var/lib/postgresql/data + networks: + - notebookmark + + keycloak: + container_name: notebookmark-keycloak + image: quay.io/keycloak/keycloak:26.5.4 + restart: unless-stopped + command: + - start + environment: + KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_USER} + KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_PASSWORD} + KC_HOSTNAME: ${KEYCLOAK_URL} + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://keycloak_postgres:5432/keycloak + KC_DB_USERNAME: ${POSTGRES_USER} + KC_DB_PASSWORD: ${POSTGRES_PASSWORD} + KC_PROXY_ADDRESS_FORWARDING: "true" + KC_HTTP_ENABLED: "true" + KC_LOG_LEVEL: info + KC_FEATURES: "token-exchange" + ports: + - "8080:8080" + # Optional production TLS setup: place cert/key under docker-compose/data/certs. + # These values can remain unset for local HTTP usage. + volumes: + - ./data/certs:/etc/x509/https:ro + depends_on: + - keycloak_postgres + networks: + - notebookmark + +networks: + notebookmark: + external: true + +volumes: + postgres-data: \ No newline at end of file diff --git a/docker-compose/note-compose.yaml b/docker-compose/note-compose.yaml new file mode 100644 index 0000000..e732a12 --- /dev/null +++ b/docker-compose/note-compose.yaml @@ -0,0 +1,53 @@ +name: notebookmark-app + +services: + api: + image: fboucher/notebookmark-api:alpha-latest + container_name: notebookmark-api + restart: unless-stopped + environment: + OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true" + OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true" + OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" + ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" + HTTP_PORTS: "8000" + ConnectionStrings__nb-tables: ${NB_STORAGE_OUTPUTS_TABLEENDPOINT} + ConnectionStrings__nb-blobs: ${NB_STORAGE_OUTPUTS_BLOBENDPOINT} + ports: + - "8001:8000" + - "8003:8002" + networks: + - notebookmark + + blazor-app: + image: fboucher/notebookmark-blazor:alpha-latest + container_name: notebookmark-blazor + restart: unless-stopped + environment: + OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES: "true" + OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES: "true" + OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY: "in_memory" + ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" + HTTP_PORTS: "8004" + services__api__http__0: "http://api:8000" + services__keycloak__http__0: "http://keycloak:8080" + ConnectionStrings__nb-tables: ${NB_STORAGE_OUTPUTS_TABLEENDPOINT} + ConnectionStrings__nb-blobs: ${NB_STORAGE_OUTPUTS_BLOBENDPOINT} + REKA_API_KEY: ${REKA_API_KEY} + Keycloak__Authority: ${KEYCLOAK_AUTHORITY} + Keycloak__ClientId: ${KEYCLOAK_CLIENT_ID} + Keycloak__ClientSecret: ${KEYCLOAK_CLIENT_SECRET} + volumes: + - ./dataprotection-keys:/root/.aspnet/DataProtection-Keys + ports: + - "8005:8004" + - "8007:8006" + depends_on: + api: + condition: service_started + networks: + - notebookmark + +networks: + notebookmark: + external: true \ No newline at end of file diff --git a/docs/docker-compose-deployment.md b/docs/docker-compose-deployment.md index acdf9e2..d48b557 100644 --- a/docs/docker-compose-deployment.md +++ b/docs/docker-compose-deployment.md @@ -1,177 +1,69 @@ # Docker Compose Deployment -This guide explains how to deploy NoteBookmark using Docker Compose, either by generating it fresh from Aspire or using the provided compose file. +This file assumes you already have: -## Two Deployment Options +- A healthy Keycloak instance +- A `notebookmark` realm configured (see [`docs/keycloak-setup.md`](keycloak-setup.md)) -### Option 1: Generate from Aspire (Recommended) +If you do not have Keycloak yet, see [`docs/keycloak-container-setup.md`](keycloak-container-setup.md) first. -Generate an up-to-date docker-compose.yaml from your Aspire AppHost configuration using the official Aspire CLI. -**Prerequisites:** -- .NET Aspire Workload installed: `dotnet workload install aspire` -- Aspire CLI installed: Included with the Aspire workload +## Prerequisites -**Steps:** +- Docker Engine with Compose support (`docker compose`) +- `docker-compose/.env` with valid values +- Azure Storage endpoints (Table + Blob) +- Keycloak client secret for client `notebookmark` -1. **Build container images locally:** - - The generated docker-compose file references image names (e.g., `notebookmark-api`, `notebookmark-blazor`), but these images don't exist until you build them. Build and tag the images with the expected names: - - ```bash - # Build API image - dotnet publish src/NoteBookmark.Api/NoteBookmark.Api.csproj -c Release -t:PublishContainer - - # Build Blazor app image - dotnet publish src/NoteBookmark.BlazorApp/NoteBookmark.BlazorApp.csproj -c Release -t:PublishContainer - ``` - - These commands build the projects and create Docker images tagged as `notebookmark-api:latest` and `notebookmark-blazorapp:latest` (based on your project names). The container names `notebookmark-api` and `notebookmark-blazor` are what the running containers will be called. +## 1. Prepare Environment Values -2. **Publish the application (generates Docker Compose files):** - ```bash - aspire publish --output-path ./aspire-output --project-name notebookmark - ``` - - **Parameters:** - - `--output-path`: Directory where docker-compose files will be generated (default: `aspire-output`) - - `--project-name`: Docker Compose project name (sets `name:` at the top of docker-compose.yaml) - - Without this, the project name defaults to the output directory name - - Affects container names: `notebookmark-api`, `notebookmark-blazor` vs `aspire-output-api`, `aspire-output-blazor` - - This command generates: - - `docker-compose.yaml` from the AppHost configuration - - `.env` file template with expected parameters (unfilled) - - Supporting infrastructure files (Bicep, Azure configs if applicable) +From the repository root: -3. **Fill in environment variables:** - Edit `./aspire-output/.env` and replace placeholder values with your actual configuration: - - Azure Storage connection strings - - Keycloak admin password and client secrets - - Any other environment-specific settings - -4. **Deploy (optional - full workflow):** - ```bash - aspire deploy --output-path ./aspire-output - ``` - This performs the complete workflow: publishes, prepares environment configs, builds images, and runs `docker compose up`. - - Or manually run Docker Compose from the output directory: - ```bash - cd aspire-output - docker compose up -d - ``` - -This ensures your docker-compose file stays in sync with the latest AppHost configuration. - -> **📚 Learn more:** See the [official Aspire Docker integration documentation](https://aspire.dev/integrations/compute/docker/) for advanced scenarios like environment-specific configs and custom image tagging. - -### Option 2: Use the Provided Compose File (Quick Start) - -For a quick start, you can use the checked-in docker-compose.yaml file located in the `docker-compose/` directory. This file was generated from Aspire and committed to the repository for convenience. - -**When to use this option:** -- You want to quickly test the application without regenerating compose files -- You're deploying a stable release version -- You haven't modified the AppHost configuration - -**Important:** If you've modified `src/NoteBookmark.AppHost/AppHost.cs`, use Option 1 to regenerate the compose file to reflect your changes. - -## Environment Configuration - -The docker-compose.yaml file uses environment variables for configuration. You must create a `.env` file in the same directory as your docker-compose.yaml file. - -### What the .env File Is For - -The `.env` file contains sensitive configuration values needed for production deployment: - -- **Database connection strings**: Connection to Azure Table Storage and Blob Storage -- **Keycloak configuration**: Authentication server settings (authority URL, client credentials) -- **Other runtime settings**: Any environment-specific configurations - -### Creating Your .env File - -1. Copy the `.env-sample` file from the repository root: - ```bash - cp .env-sample .env - ``` +```bash +cp .env-sample docker-compose/.env +``` -2. Edit `.env` and replace all placeholder values with your actual configuration: - - Azure Storage connection strings - - Keycloak admin password - - Keycloak client secret - - Keycloak authority URL (if different from default) +Edit `docker-compose/.env` and set all required values. -3. Keep `.env` secure and never commit it to version control (it's in .gitignore) +Important Keycloak values for NoteBookmark: -## Running the Application +- `KEYCLOAK_AUTHORITY` (for example `http://localhost:8080/realms/notebookmark`) +- `KEYCLOAK_CLIENT_ID` (default: `notebookmark`) +- `KEYCLOAK_CLIENT_SECRET` (from Keycloak client settings) -Once your `.env` file is configured: +## 2. Create Shared Network (One Time) -**If using Option 1 (Aspire-generated):** ```bash -cd aspire-output -docker compose up -d +docker network create notebookmark ``` -**If using Option 2 (checked-in file):** +Then move into the compose folder so `.env` is auto-detected: + ```bash cd docker-compose -docker compose up -d ``` -Access the application at: -- **Blazor App**: http://localhost:8005 -- **API**: http://localhost:8001 -- **Keycloak**: http://localhost:8080 - -**First-time setup:** Keycloak needs to be configured with the realm settings. See [Keycloak Setup Guide](./keycloak-setup.md) for detailed instructions. - -## Stopping the Application +## 3. Start NoteBookmark App ```bash -docker compose down +docker compose -f note-compose.yaml up -d ``` -To also remove volumes (WARNING: This deletes Keycloak data): - -```bash -docker compose down -v -``` +## 4. Access Services -## Advanced Deployment Workflows +- Blazor App: `http://localhost:8005` +- API: `http://localhost:8001` -The Aspire CLI supports environment-specific deployments: +## 5. Stop NoteBookmark App -**Prepare for a specific environment:** ```bash -# For staging -aspire do prepare-docker-env --environment staging - -# For production -aspire do prepare-docker-env --environment production +docker compose -f note-compose.yaml down ``` -This generates environment-specific `.env` files and builds container images. +## Quick Validation -**Clean up a deployment:** ```bash -aspire do docker-compose-down-docker-env +docker compose -f note-compose.yaml config ``` -This stops and removes all containers, networks, and volumes. - -## Notes - -- **Development vs Production:** - - In development (`dotnet run`), Aspire manages Keycloak automatically via `AddKeycloak()` - - In production (docker-compose), Keycloak runs as a containerized service - - The AppHost uses `AddDockerComposeEnvironment("docker-env")` to signal Azure Container Apps deployment intent - -- **Service Discovery:** - - Development: Aspire service discovery wires up connections automatically - - Production: Services connect via explicit environment variables in `.env` - -- **Data Persistence:** - - Keycloak data persists in a named volume (`keycloak-data`) - - Use `docker compose down -v` carefully — it deletes all data including Keycloak configuration + diff --git a/docs/keycloak-container-setup.md b/docs/keycloak-container-setup.md new file mode 100644 index 0000000..9f3ed6c --- /dev/null +++ b/docs/keycloak-container-setup.md @@ -0,0 +1,74 @@ +# Keycloak Container Setup (If You Do Not Have Keycloak Yet) + +Use this file only to get a Keycloak container running for NoteBookmark. + +After Keycloak is up, continue with: + +1. [`docs/keycloak-setup.md`](keycloak-setup.md) to configure realm/client +2. [`docs/docker-compose-deployment.md`](docker-compose-deployment.md) to run NoteBookmark + +## Official References + +- Keycloak container guide: +- Keycloak configuration docs: + +## 1. Prepare Environment File + +From repository root: + +```bash +cp .env-sample docker-compose/.env +``` + +Set at least these values in `docker-compose/.env`: + +```env +KEYCLOAK_USER=admin +KEYCLOAK_PASSWORD=change-me +KEYCLOAK_URL=localhost +POSTGRES_USER=keycloak +POSTGRES_PASSWORD=change-me +``` + +## 2. Create Shared Network (One Time) + +```bash +docker network create notebookmark +``` + +Then move into the compose folder so `.env` is auto-detected: + +```bash +cd docker-compose +``` + +## 3. Start Keycloak Stack + +```bash +docker compose -f keycloak-compose.yaml up -d +``` + +This starts: + +- `keycloak_postgres` +- `keycloak` + +Keycloak admin console: `http://localhost:8080` + +## 4. Stop Keycloak Stack + +```bash +docker compose -f keycloak-compose.yaml down +``` + +Remove Keycloak database volume (deletes Keycloak data): + +```bash +docker compose -f keycloak-compose.yaml down -v +``` + +## Quick Validation + +```bash +docker compose -f keycloak-compose.yaml config +``` diff --git a/docs/keycloak-setup.md b/docs/keycloak-setup.md index f62248c..523f251 100644 --- a/docs/keycloak-setup.md +++ b/docs/keycloak-setup.md @@ -1,82 +1,62 @@ -# Keycloak Authentication Setup +# Keycloak Realm Setup For NoteBookmark -## Overview +This file explains only how to configure Keycloak for NoteBookmark. -NoteBookmark now requires authentication via Keycloak (or any OpenID Connect provider). Only the home page is accessible without authentication - all other pages require a logged-in user. +If you do not have a Keycloak server yet, use [`docs/keycloak-container-setup.md`](keycloak-container-setup.md) first. -## Configuration +## Official References -### 1. Keycloak Server Setup +- Keycloak server administration guide: +- Keycloak securing applications (OIDC clients): -You'll need a Keycloak server running. For local development: +## 1. Create Realm -```bash -docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:latest start-dev -``` +In the Keycloak admin console, create a realm named: -### 2. Create a Realm +- `notebookmark` -1. Log into Keycloak admin console (http://localhost:8080) -2. Create a new realm called "notebookmark" +## 2. Create OIDC Client -### 3. Create a Client +In realm `notebookmark`, create a client with: -1. In the realm, create a new client: - - Client ID: `notebookmark` - - Client Protocol: `openid-connect` - - Access Type: `confidential` - - Valid Redirect URIs: `https://localhost:5001/*` (adjust for your environment) - - Web Origins: `https://localhost:5001` (adjust for your environment) +- Client ID: `notebookmark` +- Protocol: OpenID Connect +- Client authentication: Enabled (confidential client) +- Standard flow: Enabled -2. Get the client secret from the Credentials tab +Set redirect and origin values for your app URL. -### 4. Configure the Application +Local example: -Update `appsettings.json` or environment variables: +- Valid redirect URIs: `http://localhost:8005/*` +- Valid post logout redirect URIs: `http://localhost:8005/*` +- Web origins: `http://localhost:8005` -```json -{ - "Keycloak": { - "Authority": "http://localhost:8080/realms/notebookmark", - "ClientId": "notebookmark", - "ClientSecret": "your-client-secret-here" - } -} -``` +Then copy the generated client secret. -**Environment Variables (recommended for production):** +## 3. Map Keycloak Values To NoteBookmark -```bash -export Keycloak__Authority="https://your-keycloak-server/realms/notebookmark" -export Keycloak__ClientId="notebookmark" -export Keycloak__ClientSecret="your-secret" -``` +Use these values in `docker-compose/.env`: -### 5. Add Users - -In Keycloak, create users in the realm who should have access to your private website. +```env +KEYCLOAK_AUTHORITY=http://localhost:8080/realms/notebookmark +KEYCLOAK_CLIENT_ID=notebookmark +KEYCLOAK_CLIENT_SECRET=your-client-secret +``` -## How It Works +These are consumed by `docker-compose/note-compose.yaml`: -- **Home page (/)**: Public - no authentication required -- **All other pages**: Protected with `[Authorize]` attribute -- **Login/Logout**: UI in the header shows login button when not authenticated -- **Session**: Uses cookie-based authentication with OpenID Connect +- `Keycloak__Authority: ${KEYCLOAK_AUTHORITY}` +- `Keycloak__ClientId: ${KEYCLOAK_CLIENT_ID}` +- `Keycloak__ClientSecret: ${KEYCLOAK_CLIENT_SECRET}` -## Technical Details +## 4. Validate Before Running NoteBookmark -- Uses `Microsoft.AspNetCore.Authentication.OpenIdConnect` package -- Cookie-based session management -- Authorization state cascaded throughout the component tree -- `AuthorizeRouteView` in Routes.razor handles route-level protection +Check that: -## Files Modified +- Realm is exactly `notebookmark` +- Client ID is exactly `notebookmark` +- Client secret in `.env` matches Keycloak +- Redirect URI matches your app URL -- `Program.cs`: Added authentication middleware and configuration -- `Routes.razor`: Changed to `AuthorizeRouteView` for authorization support -- `MainLayout.razor`: Added `LoginDisplay` component to header -- `_Imports.razor`: Added authorization namespaces -- All pages except `Home.razor`: Added `@attribute [Authorize]` -- `Components/Shared/LoginDisplay.razor`: New component for login/logout UI -- `Components/Pages/Login.razor`: Login page -- `Components/Pages/Logout.razor`: Logout page +After that, run NoteBookmark using [`docs/docker-compose-deployment.md`](docker-compose-deployment.md).