Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ __debug_*
config.certify.yml

# deepsec
/.deepsec
/.deepsec/

# jetbrains
/.idea/

# claude stuff
/.claude/
151 changes: 151 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Agents

*This file is written by Humans for Agents.*

## Overview

Tinyauth is a lightweight and open-source authentication server written in Go and TypeScript (React). It acts as either an authentication middleware (forward_auth, ext_authz or auth_request) to protect applications using proxy authentication or as an OpenID Connect provider to offer SSO (Single-Sign-On) to your self-hosted apps. It supports 2FA (via TOTP), LDAP, access controls (ACLs), local users and SSO users via OAuth. Tinyauth can be deployed with Docker, Kubernetes or bare-metal with a binary.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Tinyauth is a lightweight and open-source authentication server written in Go and TypeScript (React). It acts as either an authentication middleware (forward_auth, ext_authz or auth_request) to protect applications using proxy authentication or as an OpenID Connect provider to offer SSO (Single-Sign-On) to your self-hosted apps. It supports 2FA (via TOTP), LDAP, access controls (ACLs), local users and SSO users via OAuth. Tinyauth can be deployed with Docker, Kubernetes or bare-metal with a binary.
Tinyauth is a lightweight and open-source authentication server written in Go and TypeScript (React). It acts as either an authentication middleware (forward_auth, ext_authz or auth_request) to protect applications using proxy authentication or as an OpenID Connect provider to offer SSO (Single-Sign-On) to your self-hosted apps. It supports local users with optional 2FA (via TOTP), LDAP, SSO users via OAuth, and access controls (ACLs). Tinyauth can be deployed with Docker, Kubernetes or bare-metal with a binary.


## Considerations

- The repository we are working at is `https://github.com/tinyauthapp/tinyauth`.
- ALWAYS follow the instructions for committing and creating a pull request as mentioned below.

## Philosophy

Tinyauth is designed to run with simplicity in mind. This is why we try to avoid adding unnecessary persistent storage and configuration options.

Tinyauth can run without persistent storage and the SQLite database is only used for storing normal or OpenID Connect sessions. You MUST never store data in the database that are required for Tinyauth function.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: "... never store data that are is required for ..."


As for the configuration, we support environment variables, CLI flags and a YAML configuration file. We try to keep the required configuration at a minimal with sane defaults so users can spend the least amount of time configuring Tinyauth.

We NEVER create a breaking change unless absolutely necessary and only if non-breaking changes have been discussed and deemed not ideal.

## Technical Overview

Tinyauth is designed to be as modular as possible. We utilize a repository-service-controller structure where each service/controller/middleware defines its dependencies in a Dig input struct and then the main bootstrap entrypoint dynamically injects the dependencies to each method.

All methods share one global static config struct which contains the user configuration as is, and a runtime config struct that contains dynamically generated values on startup. If a method needs a modified version, it MUST never modify the global configuration struct but rather create a local copy.

We write database migrations by hand. Migrations go in the respective database directory inside the `assets/migrations` directory and follow the `000001_migration_name_in_snake_case.sql` format where the 6 digit number is incremented on each new migration. The repository is automatically generated from SQL queries, SQLC and our own custom generator that unifies each SQLC package into one repository interface. Always ensure that migrations and queries exist for all available database drivers else our store generation will fail. After adding your migrations and queries, run the SQLC code-gen with `make sql` and update the store code-gen with `make generate`. DO NOT EDIT the automatically generated files from SQLC or our store generator, they are marked.

When updating translations, you should only update the `frontend/src/lib/i18n/locales/en.json` and `frontend/src/lib/i18n/locales/en-US.json` files (they should be exactly the same). Crowdin will handle the generation of the keys for the rest of the available locales. NEVER hard-code plain English in the frontend, instead use the available `i18next` library and the respective translations.

For the REST framework we use Gin. However functions or methods should avoid using the Gin Context (`gin.Context`) and default to stdlib arguments and outputs. The Gin Context is compatible with all stdlib declarations so it will not pose any issues with them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

go doc github.com/gin-gonic/gin.Context
rg -n --glob '*.go' 'gin\.Context|http\.ResponseWriter|\*http\.Request' .

Repository: tinyauthapp/tinyauth

Length of output: 13717


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '28,38p' AGENTS.md
go doc github.com/gin-gonic/gin.ResponseWriter
go doc net/http.Handler

Repository: tinyauthapp/tinyauth

Length of output: 4531


Correct the gin.Context compatibility guidance.

*gin.Context is not compatible with all standard-library signatures. Pass c.Request and c.Writer to functions that require *http.Request and http.ResponseWriter, or use an adapter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` at line 34, Correct the Gin guidance to state that *gin.Context is
not compatible with all standard-library signatures; instruct callers to pass
c.Request and c.Writer for functions requiring *http.Request or
http.ResponseWriter, or use an appropriate adapter.

Source: MCP tools


When you need to log in the backend, use the injected logger, NOT the global zerolog struct.

In case you need toolchain versions, you can find the Node + Go version in the `Dockerfile` and the PNPM version in the `package.json` file inside the `frontend` directory.

Tinyauth uses Semantic Versioning (SemVer) for versions.

## File structure

Tinyauth is composed of two parts, the React frontend and the Go backend.

A high level of the backend is as follows:

```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add language identifiers to the fenced code blocks.

markdownlint-cli2 reports MD040 for these five fence openings. Use text for the directory trees and branch-name examples.

Proposed fix
-```
+```text

Based on static analysis, markdownlint-cli2 reports MD040 on these lines.

Also applies to: 73-73, 133-133, 139-139, 145-145

🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 48-48: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` at line 48, Add the text language identifier to all five fenced
code block openings in AGENTS.md, including the directory-tree and branch-name
examples, so each uses a text-labeled fence and satisfies MD040.

Source: Linters/SAST tools

internal
├── assets # Contains the embedded assets
│   ├── dist # Dist is the compiled frontend
│   └── migrations # Migrations in SQL for all supported databases
│   ├── postgres
│   └── sqlite
├── bootstrap # The main entrypoint that bootstraps and starts Tinyauth, called by the CLI
├── controller # All of the HTTP controllers
├── middleware # The HTTP middlewares
├── model # Configuration schemas
├── repository # Repository holds all of the queries used by the services, each child-repository implements the store interface
│   ├── memory
│   ├── postgres
│   └── sqlite
├── service # The services that handle the underlying logic for the controllers
├── test # Creates any necessary package-wide configurations and helpers used by tests
└── utils # Small helpers and utils used by the app
├── decoders # Wrappers around paerser decoders such as the label decoder
├── loaders # The env, cli and YAML wrappers around the paerser loaders
└── logger # A wrapper around the zerolog logging library
```

Same for the frontend:

```
frontend/src
├── components # Different components used by the pages
│   ├── auth # Forms used for authentication
│   ├── domain-warning # Domain warning when configured domain and actual domain don't match
│   ├── icons # Hardcoded SVG icons for OAuth providers
│   ├── layout # Main frontend layout
│   ├── providers # Different state providers such as theme
│   ├── quick-actions # The top right quick settings menu
│   └── ui # ShadCN based UI components
├── context # Holds and provides the app and user context
├── lib # Helpers used by the pages
│   ├── hooks # Hooks around the query parameters
│   └── i18n # Holds translation logic
│   └── locales # The raw JSON locales provided by Crowdin
├── pages # The actual app pages
└── schemas # Different schemas, mostly used for fetching data from the backend
```

## Make recipes

Tinyauth utilizes a Makefile for simplifying development. A reference of the available recipes can be found below:

- `deps` - Install the frontend and backend dependencies.
- `clean-data` - Clean any data created by running Tinyauth.
- `clean-webui` - Clean frontend build output.
- `webui` - Compile the WebUI.
- `binary` - Compile the binary for the current system.
- `binary-linux-amd64` - Compile the binary for Linux amd64.
- `binary-linux-arm64` - Compile the binary for Linux arm64.
- `test` - Test the Go backend.
- `vet` - Vet the Go backend.
- `test-race` - Test the Go backend with the race detector enabled.
- `dev` - Start the Docker-based development server.
- `prod` - Start the Docker-based production deployment (used for testing pre-releases).
- `sql` - Generate the SQLC repositories.
- `generate` - Update Go code-gen.
- `docker` - Build the Docker image for the current system.
- `docker-distroless` - Build the distroless Docker image for the current system.
- `lint-webui` - Lint the frontend with ESLint.
- `fmt` - Format the Go code with the Go `fmt` tool.

## Development lifecycle

Development of Tinyauth happens inside two Docker containers. The backend is built automatically by air using a template build output for the frontend. The frontend is run with PNPM and then backend requests are routed with the help of Vite's proxy.

When developing, you should default to the `make dev` command in order to start everything in Docker and avoid platform-specific issues. If you need to test the CLI, use the `make binary` command.

After finishing with the development, test and vet the backend with `make test` and `make vet` respectively. If you believe you need to test for race conditions, use `make test-race`. You can also test specific parts of the code using the normal `go test` command, for example to run the `TestHealthController` test, you can use `go test ./internal/controller/ -run TestHealthController -v`. Finally format the Go code with `make fmt`.

If you made any changes to the frontend, make sure to lint with `make lint-webui`.

NEVER run any destructive commands like `make clean-data` or delete any configurations without the user's approval.

## Creating a pull request

When committing you MUST use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) standard for your commit messages. You can add a commit description if you like. You MUST also use your standard noreply Co-Author trailer.

You should work in separate branches unless it's clearly specified to work in the main branch. When working in a separate branch, follow the naming convention below:

```
[feat/refactor/fix/tests/docs/deps/etc]/[small-change-description-in-kebab-case]
```

For example, if your change was to add OAuth to Tinyauth, the branch would look as follows:

```
feat/oauth
```

Or:

```
feat/add-oauth-support
```

The smaller branch name, the better.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like Shorter branch names that still describe the general change are preferred ?


Finally, when creating the actual pull request and if you have access to the internet/a GitHub tool, you should look if it resolves any open issues and if it does, reference them.
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,11 @@ docker-distroless:
--build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) \
--build-arg=BUILD_TAGS=$(BUILD_TAGS) \
-f Dockerfile.distroless .

# Lint the frontend
lint-webui:
cd frontend && pnpm lint

# Format the code
fmt:
go fmt ./...