Commit Graph

36 Commits

Author SHA1 Message Date
Olivier Dumont
5ec9989189 Remove redundant 'openid' scope special case logic
The special case for adding 'openid' scope was redundant and could
potentially bypass client scope restrictions. The main loop already
correctly adds 'openid' to validScopes if it's in both requestedScopes
and allowedScopes.

Since 'openid' is already in the default scopes during client
configuration (SyncClientsFromConfig), it will be available for
clients that don't explicitly configure scopes. Clients can include
or exclude 'openid' in their allowedScopes as needed.

This ensures consistent enforcement of client scope restrictions
with no special-case bypasses.
2025-12-30 13:52:01 +01:00
Olivier Dumont
ad12110fbf Replace SHA256 with HKDF for key derivation and fix scope validation
Security improvements:

1. HKDF key derivation:
   - Replace raw sha256.Sum256() with proper HKDF (HMAC-based KDF)
   - Uses domain-separated label 'oidc-aes-256-key-v1' for key derivation
   - Applied to both encryptPrivateKey and decryptPrivateKey
   - Provides better security properties than raw hash

2. Scope validation fix:
   - Only add 'openid' scope if it's both requested AND in client's
     allowedScopes
   - Prevents bypassing client scope restrictions
   - Respects configured allowedScopes

Both changes improve security posture while maintaining backward
compatibility.
2025-12-30 13:37:43 +01:00
Olivier Dumont
ca74534048 Add bcrypt hashing for client secrets and RSA key encryption
Security improvements:

1. Client secret hashing:
   - Replace plaintext comparison with bcrypt.CompareHashAndPassword
   - Provides constant-time comparison to prevent timing attacks
   - Hash secrets with bcrypt before storing in database
   - Update SyncClientsFromConfig to hash incoming plaintext secrets

2. Deterministic RSA key loading:
   - Load most recently created key using ORDER BY created_at DESC
   - Add warning if multiple keys detected in database
   - Ensures consistent key selection on startup

3. Optional RSA key encryption:
   - Encrypt private keys with AES-256-GCM when OIDC_RSA_MASTER_KEY is set
   - Master key derived via SHA256 from environment variable
   - Backward compatible: stores plaintext if no master key set
   - Automatic detection of encrypted vs plaintext on load

All changes maintain backward compatibility with existing deployments.
2025-12-30 13:26:06 +01:00
Olivier Dumont
1b37096b58 CRITICAL: Add replay protection for authorization codes
Authorization codes were implemented as stateless JWTs with no tracking,
allowing the same code to be exchanged for tokens multiple times. This
violates OAuth 2.0 RFC 6749 Section 4.1.2 which mandates that authorization
codes MUST be single-use.

This change:
- Adds oidc_authorization_codes table to track code usage
- Stores authorization codes in database when generated
- Validates code exists and hasn't been used before exchange
- Marks code as used immediately after validation
- Prevents replay attacks where intercepted codes could be reused

Security impact:
- Prevents attackers from reusing intercepted authorization codes
- Ensures compliance with OAuth 2.0 security requirements
- Adds database-backed single-use enforcement
2025-12-30 13:00:19 +01:00
Olivier Dumont
cd068d16c2 Fix Python scoping issue: rename html variable to avoid conflict
The variable 'html' was being assigned to store HTML content, which
caused Python to treat 'html' as a local variable throughout the
function. This prevented access to the 'html' module (imported at
the top) within f-strings that referenced html.escape().

Renamed the HTML content variable to 'html_content' to avoid the
naming conflict with the html module.
2025-12-30 12:52:53 +01:00
Olivier Dumont
dabb4398ad Implement PKCE (Proof Key for Code Exchange) support
PKCE was advertised in the discovery document but not actually implemented.
This commit adds full PKCE support:

- Store code_challenge and code_challenge_method in authorization code JWT
- Accept code_verifier parameter in token endpoint
- Validate code_verifier against stored code_challenge
- Support both S256 (SHA256) and plain code challenge methods
- PKCE validation is required when code_challenge is present

This prevents authorization code interception attacks by requiring
the client to prove possession of the code_verifier that was used
to generate the code_challenge.
2025-12-30 12:39:00 +01:00
Olivier Dumont
ef157ae9ba Fix critical security issue: verify JWT signature in access token validation
The validateAccessToken method was only decoding the JWT payload without
verifying the signature, allowing attackers to forge tokens. This fix:

- Adds ValidateAccessToken method to OIDCService that properly verifies
  JWT signature using RSA public key
- Validates issuer, expiration, and required claims
- Updates controller to use the secure validation method
- Removes insecure manual JWT parsing code
2025-12-30 12:36:30 +01:00
Olivier Dumont
020fcb9878 Add OIDC provider functionality with validation setup
This commit adds OpenID Connect (OIDC) provider functionality to tinyauth,
allowing it to act as an OIDC identity provider for other applications.

Features:
- OIDC discovery endpoint at /.well-known/openid-configuration
- Authorization endpoint for OAuth 2.0 authorization code flow
- Token endpoint for exchanging authorization codes for tokens
- ID token generation with JWT signing
- JWKS endpoint for public key distribution
- Support for PKCE (code challenge/verifier)
- Nonce validation for ID tokens
- Configurable OIDC clients with redirect URIs, scopes, and grant types

Validation:
- Docker Compose setup for local testing
- OIDC test client (oidc-whoami) with session management
- Nginx reverse proxy configuration
- DNS server (dnsmasq) for custom domain resolution
- Chrome launch script for easy testing

Configuration:
- OIDC configuration in config.yaml
- Example configuration in config.example.yaml
- Database migrations for OIDC client storage
2025-12-30 12:17:55 +01:00
Stavros
43487d44f7 feat: forward sub from oidc providers (#543)
* feat: forward sub from oidc providers

* fix: review comments
2025-12-26 19:02:51 +02:00
Stavros
2d8af0510e feat: refresh session cookie when session is active (#540)
* feat: refresh session cookie when session is active

* refactor: use current time to set new expiry
2025-12-26 17:55:54 +02:00
Stavros
a1c3e416b6 refactor: use proper module name (#542)
* chore: reorganize go mod

* refactor: use proper module name
2025-12-26 17:53:24 +02:00
Stavros
03ed18343e feat: unified config (#533)
* chore: add yaml config ref

* feat: add initial implementation of a traefik like cli

* refactor: remove dependency on traefik

* chore: update example env

* refactor: update build

* chore: remove unused code

* fix: fix translations not loading

* feat: add experimental config file support

* chore: mod tidy

* fix: review comments

* refactor: move tinyauth to separate package

* chore: add quotes to all env variables

* chore: resolve go mod and sum conflicts

* chore: go mod tidy

* fix: review comments
2025-12-22 22:13:40 +02:00
Modestas Rinkevičius
3961589f1e feat: auto-create database directory if missing (#510) 2025-12-11 14:43:57 +02:00
Stavros
6d663bb1e8 fix: use unix seconds in db cleanup 2025-11-15 11:45:19 +02:00
Stavros
e23f4f1371 chore: disable env acls 2025-11-04 17:48:45 +02:00
Chris Ellrich
c5bb389258 feat: ACL labels from environment variables (#422)
* feat: add LabelService to retrieve application labels from environment variables

* feat: allow usage of labels from docker and env variables simultaneously

Prioritize labels from environment variables over labels from docker
labels

* fix: handle error returned by label_serive.go/LoadLabels

see https://github.com/steveiliop56/tinyauth/pull/422#discussion_r2443443032

* refactor(label_service): use simple loop instead of slices.ContainsFunc to avoid experimental slices package
see https://github.com/steveiliop56/tinyauth/pull/422#pullrequestreview-3354632045

* refactor: merge acl logic into one service

---------

Co-authored-by: Stavros <steveiliop56@gmail.com>
2025-10-21 16:02:31 +03:00
Stavros
6647c6cd78 refactor: use gorm generics api for database actions 2025-10-19 19:16:53 +03:00
Stavros
5482430907 refactor: generate a verifier on every oauth auth session 2025-10-19 19:03:38 +03:00
Stavros
64222b6d15 fix: don't use container name in label discovery 2025-10-12 11:29:31 +03:00
Stavros
9b76a84ee2 feat: add trace logging 2025-10-11 15:27:01 +03:00
Stavros
5a4855c12c refactor: move docker connection check to start up 2025-10-10 15:45:04 +03:00
Stavros
287c6f975f fix: do not allow request if docker labels check fail 2025-10-08 15:44:34 +03:00
Stavros
adffb4ac0a fix: names in oauth broker 2025-10-08 15:15:30 +03:00
Stavros
085f6257c5 fix: fix oauth group provider check 2025-09-25 22:35:44 +03:00
Stavros
e8558b89b4 fix: set gin mode correctly 2025-09-22 16:15:55 +03:00
Stavros
5c866bad1a feat: multiple oauth providers (#355)
* feat: add flag decoder (candidate)

* refactor: finalize flags decoder

* feat: add env decoder

* feat: add oauth config parsing logic

* feat: implement backend logic for multiple oauth providers

* feat: implement multiple oauth providers in the frontend

* feat: add some default icons

* chore: add credits for parser

* feat: style oauth auto redirect screen

* fix: bot suggestions

* refactor: rework decoders using simpler and more efficient pattern

* refactor: rework oauth name database migration
2025-09-16 13:28:28 +03:00
Stavros
e03eaf4f08 feat: add psl check in cookie domain 2025-09-10 13:43:08 +03:00
Stavros
f5ac7eff99 refactor: mode label decoder to separate package 2025-09-03 12:23:21 +03:00
Stavros
f3eb7f69b4 Revert "feat: header based acls (#337)" (#340)
This reverts commit f0d2da281a.
2025-09-03 12:12:18 +03:00
Stavros
f0d2da281a feat: header based acls (#337)
* feat: add header decoder

* feat: allow for dash substitute over slash for environments like kubernetes

* feat: use decoded headers in proxy controller

* refactor: simplify decode header to node function

* refactor: use stdlib prefix check in header decoder

* fix: lowercase key and filter before comparing
2025-09-02 19:06:52 +03:00
Stavros
ad4fc7ef5f refactor: don't export non-needed fields (#336)
* refactor: don't export non-needed fields

* feat: coderabbit suggestions

* fix: avoid queries panic
2025-09-02 01:27:55 +03:00
Stavros
5184c96e85 feat: add mutex to ldap service 2025-09-02 00:08:19 +03:00
Stavros
b9e35716ac feat: invalid domain warning (#332)
* wip

* refactor: update domain warning layout

* i18n: add domain warning translations

* refactor: rework hooks usage

* feat: clear timeouts

* fix: use useeffect to cleanup timeout

* refactor: rework redirects and history storage

* refactor: rename domain to root domain
2025-09-01 18:22:42 +03:00
Stavros
c7c3de4f78 refactor: unify labels (#329)
* refactor: unify labels

* feat: implement path block and user block

Fixes #313

* fix: fix oauth group check logic

* chore: fix typo
2025-08-29 17:04:34 +03:00
Stavros
03d06cb0a7 feat: add sqlite database for storing sessions (#326)
* feat: add sqlite database for storing sessions

* refactor: use db instance instead of service in auth service

* fix: coderabbit suggestions
2025-08-29 12:35:11 +03:00
Stavros
504a3b87b4 refactor: rework file structure (#325)
* wip: add middlewares

* refactor: use context fom middleware in handlers

* refactor: use controller approach in handlers

* refactor: move oauth providers into services (non-working)

* feat: create oauth broker service

* refactor: use a boostrap service to bootstrap the app

* refactor: split utils into smaller files

* refactor: use more clear name for frontend assets

* feat: allow customizability of resources dir

* fix: fix typo in ui middleware

* fix: validate resource file paths in ui middleware

* refactor: move resource handling to a controller

* feat: add some logging

* fix: configure middlewares before groups

* fix: use correct api path in login mutation

* fix: coderabbit suggestions

* fix: further coderabbit suggestions
2025-08-26 15:05:03 +03:00