Benjamin 0015af12e1 feat: add silent OAuth login with auto-authentication
- Add ACKIFY_OAUTH_AUTO_LOGIN config flag (default: false)
- Implement /api/auth/check endpoint for session validation
- Add silent login flow with prompt=none OAuth parameter
- Implement localStorage-based retry prevention (5min cooldown)
- Add comprehensive OAuth flow debugging logs
- Handle OAuth errors gracefully (login_required, interaction_required)
- Update templates with silent login JavaScript
- Add login button in header when not authenticated
- Fix /health endpoint documentation (remove /healthz alias)
- Extend tests to include autoLogin parameter
2025-10-06 13:13:17 +02:00
2025-09-20 12:27:20 +02:00
2025-10-06 13:02:13 +02:00

🔐 Ackify

Proof of Read. Compliance made simple.

Secure document reading validation service with cryptographic traceability and irrefutable proof.

Build Security Go License

🇫🇷 Version française disponible ici

Visite our website here : https://www.ackify.eu

🎯 Why Ackify?

Problem: How to prove that a collaborator has actually read and understood an important document?

Solution: Ed25519 cryptographic signatures with immutable timestamps and complete traceability.

Real-world use cases

  • Security policy validation
  • Mandatory training attestations
  • GDPR acknowledgment
  • Contractual acknowledgments
  • Quality and compliance procedures

📸 Vidéos

Click to GIFs for open videos WebM in your browser.

1) Create sign
Initialisation d’une signature
2) User sign flow
Parcours de signature utilisateur

📸 Screenshots

Home page
Home page
Signing request
Signing request
Signature confirmed
Signature confirmed
Signatures list
Signatures list
Outline integration
Outline integration
Google Docs integration
Google Docs integration

Quick Start

git clone https://github.com/btouchard/ackify-ce.git
cd ackify-ce

# Minimal configuration
cp .env.example .env
# Edit .env with your OAuth2 settings

# Start
docker compose up -d

# Test
curl http://localhost:8080/health   # alias: /health

Required variables

ACKIFY_BASE_URL="https://your-domain.com"
ACKIFY_OAUTH_CLIENT_ID="your-oauth-client-id"        # Google/GitHub/GitLab
ACKIFY_OAUTH_CLIENT_SECRET="your-oauth-client-secret"
ACKIFY_DB_DSN="postgres://user:password@localhost/ackify?sslmode=disable"
ACKIFY_OAUTH_COOKIE_SECRET="$(openssl rand -base64 32)"

🚀 Simple Usage

1. Request a signature

https://your-domain.com/sign?doc=security_procedure_2025

→ User authenticates via OAuth2 and validates their reading

2. Verify signatures

# JSON API - Complete list
curl "https://your-domain.com/status?doc=security_procedure_2025"

# PNG Badge - Individual status  
curl "https://your-domain.com/status.png?doc=security_procedure_2025&user=john.doe@company.com"

3. Integrate into your pages

<!-- Embeddable widget -->
<iframe src="https://your-domain.com/embed?doc=security_procedure_2025" 
        width="500" height="300"></iframe>

<!-- Via oEmbed -->
<script>
fetch('/oembed?url=https://your-domain.com/embed?doc=security_procedure_2025')
  .then(r => r.json())
  .then(data => document.getElementById('signatures').innerHTML = data.html);
</script>

🔧 OAuth2 Configuration

Supported providers

Provider Configuration
Google ACKIFY_OAUTH_PROVIDER=google
GitHub ACKIFY_OAUTH_PROVIDER=github
GitLab ACKIFY_OAUTH_PROVIDER=gitlab + ACKIFY_OAUTH_GITLAB_URL
Custom Custom endpoints

Custom provider

# Leave ACKIFY_OAUTH_PROVIDER empty
ACKIFY_OAUTH_AUTH_URL="https://auth.company.com/oauth/authorize"
ACKIFY_OAUTH_TOKEN_URL="https://auth.company.com/oauth/token"
ACKIFY_OAUTH_USERINFO_URL="https://auth.company.com/api/user"
ACKIFY_OAUTH_SCOPES="read:user,user:email"

Domain restriction

ACKIFY_OAUTH_ALLOWED_DOMAIN="@company.com"  # Only @company.com emails

Log level setup

ACKIFY_LOG_LEVEL="info" # can be debug, info, warn(ing), error. default: info

🛡️ Security & Architecture

Cryptographic security

  • Ed25519: State-of-the-art digital signatures
  • SHA-256: Payload hashing against tampering
  • Immutable timestamps: PostgreSQL triggers
  • Encrypted sessions: Secure cookies
  • CSP headers: XSS protection

Go architecture

cmd/ackapp/              # Entry point
internal/
  domain/                # Business logic
    models/              # Entities
    repositories/        # Persistence interfaces
  application/           # Use cases  
    services/            # Business implementations
  infrastructure/        # Adapters
    auth/               # OAuth2
    database/           # PostgreSQL
    config/             # Configuration
  presentation/          # HTTP
    handlers/           # Controllers + interfaces
    templates/          # HTML views
pkg/                    # Shared utilities

Technology stack

  • Go 1.24.5: Performance and simplicity
  • PostgreSQL: Integrity constraints
  • OAuth2: Multi-provider
  • Docker: Simplified deployment
  • Traefik: HTTPS reverse proxy

📊 Database

CREATE TABLE signatures (
    id BIGSERIAL PRIMARY KEY,
    doc_id TEXT NOT NULL,                    -- Document ID
    user_sub TEXT NOT NULL,                  -- OAuth user ID
    user_email TEXT NOT NULL,               -- User email
    signed_at TIMESTAMPTZ NOT NULL,     -- Signature timestamp
    payload_hash TEXT NOT NULL,         -- Cryptographic hash
    signature TEXT NOT NULL,            -- Ed25519 signature
    nonce TEXT NOT NULL,                    -- Anti-replay
    created_at TIMESTAMPTZ DEFAULT now(),   -- Immutable
    referer TEXT,                           -- Source (optional)
    prev_hash TEXT,
    UNIQUE (doc_id, user_sub)              -- One signature per user/doc
);

Guarantees:

  • Uniqueness: One user = one signature per document
  • Immutability: created_at protected by trigger
  • Integrity: SHA-256 hash to detect modifications
  • Non-repudiation: Ed25519 signature cryptographically provable

🚀 Production Deployment

docker-compose.yml

version: '3.8'
services:
  ackapp:
    image: btouchard/ackify-ce:latest
    environment:
      ACKIFY_BASE_URL: https://ackify.company.com
      ACKIFY_DB_DSN: postgres://user:pass@postgres:5432/ackdb?sslmode=require
      ACKIFY_OAUTH_CLIENT_ID: ${ACKIFY_OAUTH_CLIENT_ID}
      ACKIFY_OAUTH_CLIENT_SECRET: ${ACKIFY_OAUTH_CLIENT_SECRET}
      ACKIFY_OAUTH_COOKIE_SECRET: ${ACKIFY_OAUTH_COOKIE_SECRET}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.ackify.rule=Host(`ackify.company.com`)"
      - "traefik.http.routers.ackify.tls.certresolver=letsencrypt"

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: ackdb
      POSTGRES_USER: ackuser
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data

Production variables

# Enhanced security
ACKIFY_OAUTH_COOKIE_SECRET="$(openssl rand 64 | base64 -w 0)"
ACKIFY_ED25519_PRIVATE_KEY="$(openssl rand 64 | base64 -w 0)"

# HTTPS mandatory
ACKIFY_BASE_URL="https://ackify.company.com"

# Secure PostgreSQL
ACKIFY_DB_DSN="postgres://user:pass@postgres:5432/ackdb?sslmode=require"

📋 Complete API

Authentication

  • GET /login?next=<url> - OAuth2 login
  • GET /logout - Logout
  • GET /oauth2/callback - OAuth2 callback

Signatures

  • GET /sign?doc=<id> - Signature interface
  • POST /sign - Create signature
  • GET /signatures - My signatures (auth required)

Consultation

  • GET /status?doc=<id> - JSON all signatures
  • GET /status.png?doc=<id>&user=<email> - PNG badge

Integration

  • GET /oembed?url=<embed_url> - oEmbed metadata
  • GET /embed?doc=<id> - HTML widget

Monitoring

  • GET /health - Health check

Admin

  • GET /admin - Dashboard (restricted)
  • GET /admin/docs/{docID} - Signatures for a document
  • GET /admin/api/chain-integrity/{docID} - Chain integrity JSON

Access control: set ACKIFY_ADMIN_EMAILS with a comma-separated list of admin emails (exact match, case-insensitive). Example:

ACKIFY_ADMIN_EMAILS="alice@company.com,bob@company.com"

🔍 Development & Testing

Local build

# Dependencies
go mod tidy

# Build
go build ./cmd/community

# Linting
go fmt ./...
go vet ./...

# Tests (TODO: add tests)
go test -v ./...

Docker development

# Build image
docker build -t ackify-ce:dev .

# Run with local database
docker run -p 8080:8080 --env-file .env ackify-ce:dev

# Optional: static analysis
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...

🤝 Support

Help & Documentation

License (AGPLv3)

Distributed under the GNU Affero General Public License v3.0. See LICENSE for details.


Developed with ❤️ by Benjamin TOUCHARD

Description
Proof of Read. Compliance made simple.
Readme AGPL-3.0 36 MiB
Languages
Go 59.5%
Vue 21%
TypeScript 12.1%
Shell 3.1%
PLpgSQL 1.9%
Other 2.3%