Files
chapter-organizer/docs/authentication-setup.md
poprhythm 83522ac52c Refactor Teams components for improved sorting and filtering functionality
Updated the Teams Index and Printout components to prioritize sorting by EventFormat, enhancing the organization of team data. Introduced a regional filter toggle in the Teams Index to allow users to view only regional teams. Adjusted the ScheduledTeamsList to sort teams by EventFormat first, ensuring consistent ordering across components. Additionally, added necessary using directives for improved code clarity.
2026-01-04 14:56:28 -05:00

14 KiB

Authentication Setup Guide

This guide explains how to configure login credentials for the TSA Chapter Organizer application. The application uses BCrypt password hashing and supports multiple authentication methods depending on your environment.

Table of Contents


Overview

The TSA Chapter Organizer uses cookie-based authentication with BCrypt password hashing. User credentials are stored securely and never in plain text. The authentication system supports:

  • BCrypt password hashing (work factor 11)
  • Case-insensitive email matching
  • Role-based access control
  • Rate limiting (5 failed attempts result in 15-minute lockout)
  • Session management (20 minutes default, 30 days with "Remember Me")

Available Roles

The application supports two user roles:

  • Administrator - Full access to all features
  • Advisor - Standard user access

Roles are defined in WebApp/Authentication/AuthRoles.cs and can be customized if needed.


Generating Password Hashes

Before setting up authentication, you need to generate BCrypt hashes for your passwords. The application provides a development endpoint for this purpose.

  1. Start the application in Development mode
  2. Navigate to: https://localhost:<port>/dev/hash-password?password=YourPassword
  3. Copy the hash value from the JSON response

Example:

https://localhost:5001/dev/hash-password?password=MySecurePass123

Response:

{
  "password": "MySecurePass123",
  "hash": "$2a$11$xyz123...",
  "message": "Copy the hash value to your User Secrets configuration"
}

Method 2: Programmatic (for automation)

You can also generate hashes programmatically using the PasswordHashGenerator class:

using WebApp.Authentication;

var hash = PasswordHashGenerator.GenerateHash("YourPassword");

Development Setup

For local development, the application uses .NET User Secrets to store authentication credentials securely.

Prerequisites

  • .NET SDK installed
  • User Secrets ID configured in WebApp.csproj (already configured: 73972335-ec46-4ad6-a959-8ebe0b06147d)

Steps

  1. Generate password hashes using the development endpoint (see above)

  2. Configure User Secrets using the .NET CLI:

    cd WebApp
    
    # Set authentication configuration
    dotnet user-secrets set "Authentication:Users:0:Email" "admin@example.com"
    dotnet user-secrets set "Authentication:Users:0:PasswordHash" "$2a$11$your_hash_here"
    dotnet user-secrets set "Authentication:Users:0:Role" "Administrator"
    dotnet user-secrets set "Authentication:Users:0:DisplayName" "Administrator"
    
    # Add additional users (increment the index)
    dotnet user-secrets set "Authentication:Users:1:Email" "advisor@example.com"
    dotnet user-secrets set "Authentication:Users:1:PasswordHash" "$2a$11$your_hash_here"
    dotnet user-secrets set "Authentication:Users:1:Role" "Advisor"
    dotnet user-secrets set "Authentication:Users:1:DisplayName" "Chapter Advisor"
    
  3. Verify your configuration:

    dotnet user-secrets list
    
  4. Run the application:

    dotnet run
    
  5. Login at https://localhost:<port>/login

Example: Complete Development Setup

# 1. Navigate to WebApp directory
cd WebApp

# 2. Generate hash (via browser or curl)
# Visit: https://localhost:5001/dev/hash-password?password=admin123

# 3. Configure admin user
dotnet user-secrets set "Authentication:Users:0:Email" "admin@myschool.edu"
dotnet user-secrets set "Authentication:Users:0:PasswordHash" "$2a$11$REPLACE_WITH_GENERATED_HASH"
dotnet user-secrets set "Authentication:Users:0:Role" "Administrator"
dotnet user-secrets set "Authentication:Users:0:DisplayName" "TSA Admin"

# 4. Configure advisor user (optional)
dotnet user-secrets set "Authentication:Users:1:Email" "advisor@myschool.edu"
dotnet user-secrets set "Authentication:Users:1:PasswordHash" "$2a$11$REPLACE_WITH_GENERATED_HASH"
dotnet user-secrets set "Authentication:Users:1:Role" "Advisor"
dotnet user-secrets set "Authentication:Users:1:DisplayName" "Chapter Advisor"

# 5. Verify
dotnet user-secrets list

# 6. Run
dotnet run

Production Setup

For production environments (Docker, deployed servers), you have two options for configuring authentication credentials.

This approach allows you to edit credentials without rebuilding the container.

Steps

  1. Generate Password Hashes (on your development machine):

    • Use the development endpoint or programmatic method
  2. Create auth-secrets.json on your Docker host:

    cp auth-secrets.example.json auth-secrets.json
    
  3. Edit auth-secrets.json and replace the placeholder hashes:

    {
      "Authentication": {
        "Users": [
          {
            "Email": "admin@example.com",
            "PasswordHash": "$2a$11$actual.hash.here",
            "Role": "Administrator",
            "DisplayName": "Administrator"
          },
          {
            "Email": "advisor@example.com",
            "PasswordHash": "$2a$11$actual.hash.here",
            "Role": "Advisor",
            "DisplayName": "Chapter Advisor"
          }
        ]
      }
    }
    
  4. Set proper file permissions:

    chmod 600 auth-secrets.json
    chown root:root auth-secrets.json  # Adjust user/group as needed
    
  5. Configure Docker Compose (see docker-compose.example.yml):

    volumes:
      - ./auth-secrets.json:/app/Data/auth-secrets.json:ro
    
  6. Update credentials: Simply edit auth-secrets.json on the host and restart the container:

    docker-compose restart webapp
    

Security Note: Never commit auth-secrets.json to version control. It should be in .gitignore.

Option 2: Environment Variables

This approach is useful for container orchestration platforms (Kubernetes, Docker Swarm, etc.).

Docker Compose Example

environment:
  - TSA_Authentication__Users__0__Email=admin@example.com
  - TSA_Authentication__Users__0__PasswordHash=$2a$11$hash...
  - TSA_Authentication__Users__0__Role=Administrator
  - TSA_Authentication__Users__0__DisplayName=Administrator
  - TSA_Authentication__Users__1__Email=advisor@example.com
  - TSA_Authentication__Users__1__PasswordHash=$2a$11$hash...
  - TSA_Authentication__Users__1__Role=Advisor
  - TSA_Authentication__Users__1__DisplayName=Chapter Advisor

Docker Run Example

docker run -d \
  -p 8080:8080 \
  -e ASPNETCORE_ENVIRONMENT=Production \
  -e TSA_Authentication__Users__0__Email=admin@example.com \
  -e TSA_Authentication__Users__0__PasswordHash='$2a$11$hash...' \
  -e TSA_Authentication__Users__0__Role=Administrator \
  -e TSA_Authentication__Users__0__DisplayName=Administrator \
  tsa-chapter-organizer:latest

Kubernetes Secret Example

apiVersion: v1
kind: Secret
metadata:
  name: tsa-auth-secrets
type: Opaque
stringData:
  TSA_Authentication__Users__0__Email: "admin@example.com"
  TSA_Authentication__Users__0__PasswordHash: "$2a$11$hash..."
  TSA_Authentication__Users__0__Role: "Administrator"
  TSA_Authentication__Users__0__DisplayName: "Administrator"

Note: Environment variable names use double underscores (__) to represent nested configuration paths, with the TSA_ prefix.


Managing Users

Adding a New User

Development (User Secrets)

# Find the next available index (check existing users first)
dotnet user-secrets list | grep "Authentication:Users"

# Add new user (replace N with the next index)
dotnet user-secrets set "Authentication:Users:N:Email" "newuser@example.com"
dotnet user-secrets set "Authentication:Users:N:PasswordHash" "$2a$11$hash..."
dotnet user-secrets set "Authentication:Users:N:Role" "Advisor"
dotnet user-secrets set "Authentication:Users:N:DisplayName" "New User Name"

Production (JSON File)

  1. Edit auth-secrets.json on the host
  2. Add a new entry to the Users array:
    {
      "Email": "newuser@example.com",
      "PasswordHash": "$2a$11$hash...",
      "Role": "Advisor",
      "DisplayName": "New User Name"
    }
    
  3. Restart the container: docker-compose restart webapp

Production (Environment Variables)

Add new environment variables with the next index number and recreate the container.

Changing a Password

  1. Generate a new password hash:

    • Development: Use /dev/hash-password endpoint
    • Production: Generate on local dev machine
  2. Update the configuration:

    • Development: dotnet user-secrets set "Authentication:Users:N:PasswordHash" "$2a$11$new_hash"
    • Production (JSON): Edit auth-secrets.json and update the PasswordHash value
    • Production (Env Vars): Update the environment variable
  3. Restart the application:

    • Development: Restart the app (automatic on file change for User Secrets)
    • Production: docker-compose restart webapp

Removing a User

  1. Remove from configuration:

    • Development: Remove the User Secrets entries for that user index
    • Production (JSON): Remove the user entry from auth-secrets.json
    • Production (Env Vars): Remove the environment variables
  2. Restart the application

Note: When removing users from JSON or environment variables, you may need to renumber remaining users' indices, or leave gaps (both approaches work).


Security Best Practices

  1. Strong Passwords: Use strong, unique passwords for each user. Consider using a password manager.

  2. File Permissions (Production):

    chmod 600 auth-secrets.json
    chown root:root auth-secrets.json
    
  3. Never Commit Secrets: Ensure the following are in .gitignore:

    • auth-secrets.json
    • docker-compose.yml (if it contains secrets)
    • User Secrets files (automatically ignored by .NET)
  4. Use HTTPS in Production: Always configure SSL/TLS certificates for production deployments.

  5. Backup Credentials Securely: Store encrypted backups of auth-secrets.json in a secure location.

  6. Password Rotation: Periodically regenerate password hashes and update credentials.

  7. Monitor Access: Review application logs for failed login attempts:

    docker-compose logs webapp | grep "Failed login"
    
  8. Limit Access: Only grant Administrator role to trusted users. Use Advisor role for general access.

  9. Rate Limiting: The application automatically enforces rate limiting (5 failed attempts = 15 minute lockout). Monitor logs for suspicious activity.


Troubleshooting

Can't Login

  1. Verify configuration is loaded:

    • Development: Check User Secrets are configured: dotnet user-secrets list
    • Production: Check if file is mounted: docker exec tsa-app ls -la /app/Data/auth-secrets.json
  2. Check JSON syntax (if using JSON file):

    cat auth-secrets.json | jq .
    

    Or validate online using a JSON validator.

  3. Verify password hash: Ensure the hash was copied completely (BCrypt hashes are ~60 characters)

  4. Check application logs:

    docker-compose logs webapp | grep -i "authentication\|login"
    
  5. Verify email is correct: Email matching is case-insensitive, but ensure it matches exactly what you configured.

Rate Limited / Locked Out

If you see "Too many failed attempts" error:

  1. Wait 15 minutes for the lockout to expire
  2. Or restart the container (resets rate limit tracking):
    docker-compose restart webapp
    

Forgot Admin Password

  1. Generate a new password hash using the dev endpoint (on local dev machine)
  2. Update auth-secrets.json (production) or User Secrets (development)
  3. Restart the application

No Users Configured Error

If you see "Authentication system not configured" or "No users configured":

  1. Development: Verify User Secrets are set:

    dotnet user-secrets list | grep Authentication
    
  2. Production: Check that auth-secrets.json exists and is properly mounted:

    docker exec tsa-app cat /app/Data/auth-secrets.json
    
  3. Verify the JSON structure matches the expected format (see auth-secrets.example.json)

Container Won't Start

Check logs for configuration errors:

docker-compose logs webapp

Common issues:

  • JSON syntax error in auth-secrets.json
  • File permissions preventing file access
  • Missing required configuration values

Example: Complete Production Setup

# 1. Generate password hash locally (in development)
# Visit: https://localhost:5001/dev/hash-password?password=SecurePass123

# 2. Create secrets file
cat > auth-secrets.json <<EOF
{
  "Authentication": {
    "Users": [
      {
        "Email": "admin@myschool.edu",
        "PasswordHash": "$2a$11$paste_generated_hash_here",
        "Role": "Administrator",
        "DisplayName": "TSA Admin"
      },
      {
        "Email": "advisor@myschool.edu",
        "PasswordHash": "$2a$11$paste_generated_hash_here",
        "Role": "Advisor",
        "DisplayName": "Chapter Advisor"
      }
    ]
  }
}
EOF

# 3. Set permissions
chmod 600 auth-secrets.json

# 4. Create docker-compose.yml (copy and customize from example)
cp docker-compose.example.yml docker-compose.yml

# 5. Ensure volume mount is configured in docker-compose.yml:
# volumes:
#   - ./auth-secrets.json:/app/Data/auth-secrets.json:ro

# 6. Start the application
docker-compose up -d

# 7. Check it's running
docker-compose ps
curl http://localhost:8080

# 8. Login
# Navigate to http://localhost:8080/login
# Use configured credentials

Additional Resources

  • See DEPLOYMENT.md for Docker deployment details
  • See auth-secrets.example.json for the expected JSON structure
  • See docker-compose.example.yml for Docker Compose configuration examples
  • Authentication implementation: WebApp/Authentication/