Compare commits

..

29 Commits

Author SHA1 Message Date
Stavros
97b0d3e350 fix: use axios error instead of generic error in login page 2025-05-20 17:16:08 +03:00
Stavros
e8190456c3 feat: validate api response against zod schema 2025-05-20 17:12:39 +03:00
Stavros
02f83baa4d chore: formatting 2025-05-20 17:02:10 +03:00
Stavros
d59f35467e Merge branch 'main' into feat/new-ui 2025-05-20 16:49:19 +03:00
Stavros
00fbbfc4f2 chore: remove translations cdn 2025-05-15 16:07:38 +03:00
Stavros
76346fe835 fix: fix hook rendering 2025-05-15 16:05:21 +03:00
Stavros
03f193090d fix: fix dockerfiles 2025-05-15 15:57:12 +03:00
Stavros
3612ac0740 refactor: change select color 2025-05-15 15:50:34 +03:00
Stavros
00203722f8 fix: run oauth auto redirect only when there is a redirect URI 2025-05-14 21:00:06 +03:00
Stavros
60093997dc fix: correctly redirect to app and check for untrusted redirects 2025-05-14 20:56:24 +03:00
Stavros
ada21776bc refactor: bot suggestions 2025-05-14 20:43:18 +03:00
Stavros
b12d0655d4 chore: fix dependabot config 2025-05-14 20:26:38 +03:00
Stavros
2246ca0c13 Merge branch 'main' into feat/new-ui 2025-05-14 20:21:37 +03:00
Stavros
10dc228f6c feat: sanitize redirect URL on check 2025-05-14 20:08:48 +03:00
Stavros
28eea8d40c feat: sanitize redirect URL 2025-05-14 20:08:04 +03:00
Stavros
a4224e6771 chore: add acknowledgements for background image 2025-05-14 19:50:44 +03:00
Stavros
003f55b9ff feat: custom background image config option 2025-05-14 19:47:56 +03:00
Stavros
dbc460144e feat: favicons 2025-05-14 19:36:57 +03:00
Stavros
f05181b05d chore: rename docs back to assets 2025-05-14 19:29:28 +03:00
Stavros
28ef893456 chore: update readme and assets 2025-05-12 23:16:17 +03:00
Stavros
a488b70bbe feat: add oauth logic 2025-05-12 23:03:14 +03:00
Stavros
4e91e567b2 fix: use correct tab order in login form 2025-05-09 23:17:53 +03:00
Stavros
6453edede6 feat: finalize username login 2025-05-09 22:55:52 +03:00
Stavros
41c63e5b49 feat: user context 2025-05-09 17:39:14 +03:00
Stavros
31a7b0ff06 feat: app context 2025-05-09 16:49:54 +03:00
Stavros
0880152b48 chore: remove unused translations 2025-05-09 16:26:26 +03:00
Stavros
51532350cc feat: finalize pages 2025-05-09 16:25:12 +03:00
Stavros
56ae246ff4 feat: make forms functional 2025-05-08 18:08:56 +03:00
Stavros
fd96f39d3a wip 2025-04-29 22:36:48 +03:00
9 changed files with 35 additions and 85 deletions

View File

@@ -24,22 +24,18 @@ Tinyauth is a simple authentication middleware that adds simple username/passwor
> [!NOTE]
> Tinyauth is intended for homelab use only and it is not made for production use cases. If you are looking for something production ready please use [authentik](https://goauthentik.io) instead.
## Discord
I just made a Discord server for tinyauth! It is not only for tinyauth but general self-hosting and homelabbing. [See you there!](https://discord.gg/eHzVaCzRRd).
## Getting Started
You can easily get started with tinyauth by following the guide in the [documentation](https://tinyauth.app/docs/getting-started.html). There is also an available [docker compose file](./docker-compose.example.yml) that has traefik, whoami and tinyauth to demonstrate its capabilities.
## Demo
If you are still not sure if tinyauth suits your needs you can try out the [demo](https://demo.tinyauth.app). The default username is `user` and the default password is `password`.
## Documentation
You can find documentation and guides on all of the available configuration of tinyauth in the [website](https://tinyauth.app).
## Discord
I just made a Discord server for tinyauth! It is not only for tinyauth but general self-hosting and homelabbing. [See you there!](https://discord.gg/eHzVaCzRRd).
## Contributing
All contributions to the codebase are welcome! If you have any recommendations on how to improve security or find a security issue in tinyauth please open an issue or pull request so it can be fixed as soon as possible!

View File

@@ -2,7 +2,6 @@ package cmd
import (
"errors"
"fmt"
"os"
"strings"
"time"
@@ -68,12 +67,6 @@ var rootCmd = &cobra.Command{
HandleError(err, "Failed to get upper domain")
log.Info().Str("domain", domain).Msg("Using domain for cookie store")
// Generate cookie name
cookieId := utils.GenerateIdentifier(strings.Split(domain, ".")[0])
sessionCookieName := fmt.Sprintf("%s-%s", constants.SessionCookieName, cookieId)
csrfCookieName := fmt.Sprintf("%s-%s", constants.CsrfCookieName, cookieId)
redirectCookieName := fmt.Sprintf("%s-%s", constants.RedirectCookieName, cookieId)
// Create OAuth config
oauthConfig := types.OAuthConfig{
GithubClientId: config.GithubClientId,
@@ -100,8 +93,6 @@ var rootCmd = &cobra.Command{
ForgotPasswordMessage: config.FogotPasswordMessage,
BackgroundImage: config.BackgroundImage,
OAuthAutoRedirect: config.OAuthAutoRedirect,
CsrfCookieName: csrfCookieName,
RedirectCookieName: redirectCookieName,
}
// Create api config
@@ -112,15 +103,14 @@ var rootCmd = &cobra.Command{
// Create auth config
authConfig := types.AuthConfig{
Users: users,
OauthWhitelist: config.OAuthWhitelist,
Secret: config.Secret,
CookieSecure: config.CookieSecure,
SessionExpiry: config.SessionExpiry,
Domain: domain,
LoginTimeout: config.LoginTimeout,
LoginMaxRetries: config.LoginMaxRetries,
SessionCookieName: sessionCookieName,
Users: users,
OauthWhitelist: config.OAuthWhitelist,
Secret: config.Secret,
CookieSecure: config.CookieSecure,
SessionExpiry: config.SessionExpiry,
Domain: domain,
LoginTimeout: config.LoginTimeout,
LoginMaxRetries: config.LoginMaxRetries,
}
// Create hooks config

1
go.mod
View File

@@ -6,7 +6,6 @@ require (
github.com/gin-gonic/gin v1.10.0
github.com/go-playground/validator/v10 v10.26.0
github.com/google/go-querystring v1.1.0
github.com/google/uuid v1.6.0
github.com/mdp/qrterminal/v3 v3.2.1
github.com/rs/zerolog v1.34.0
github.com/spf13/cobra v1.9.1

View File

@@ -28,29 +28,21 @@ var apiConfig = types.APIConfig{
// Simple handlers config for tests
var handlersConfig = types.HandlersConfig{
AppURL: "http://localhost:8080",
Domain: "localhost",
DisableContinue: false,
CookieSecure: false,
Title: "Tinyauth",
GenericName: "Generic",
ForgotPasswordMessage: "Some message",
CsrfCookieName: "tinyauth-csrf",
RedirectCookieName: "tinyauth-redirect",
BackgroundImage: "https://example.com/image.png",
OAuthAutoRedirect: "none",
}
// Simple auth config for tests
var authConfig = types.AuthConfig{
Users: types.Users{},
OauthWhitelist: "",
Secret: "super-secret-api-thing-for-tests", // It is 32 chars long
CookieSecure: false,
SessionExpiry: 3600,
LoginTimeout: 0,
LoginMaxRetries: 0,
SessionCookieName: "tinyauth-session",
Domain: "localhost",
Users: types.Users{},
OauthWhitelist: "",
Secret: "super-secret-api-thing-for-tests", // It is 32 chars long
CookieSecure: false,
SessionExpiry: 3600,
LoginTimeout: 0,
LoginMaxRetries: 0,
}
// Simple hooks config for tests
@@ -214,9 +206,6 @@ func TestAppContext(t *testing.T) {
Title: "Tinyauth",
GenericName: "Generic",
ForgotPasswordMessage: "Some message",
BackgroundImage: "https://example.com/image.png",
OAuthAutoRedirect: "none",
Domain: "localhost",
}
// We should get the username back
@@ -245,7 +234,7 @@ func TestUserContext(t *testing.T) {
// Set the cookie
req.AddCookie(&http.Cookie{
Name: "tinyauth-session",
Name: "tinyauth",
Value: cookie,
})

View File

@@ -45,7 +45,7 @@ func (auth *Auth) GetSession(c *gin.Context) (*sessions.Session, error) {
}
// Get session
session, err := store.Get(c.Request, auth.Config.SessionCookieName)
session, err := store.Get(c.Request, "tinyauth")
if err != nil {
log.Error().Err(err).Msg("Failed to get session")
return nil, err

View File

@@ -21,8 +21,3 @@ type Claims struct {
var Version = "development"
var CommitHash = "n/a"
var BuildTimestamp = "n/a"
// Cookie names
var SessionCookieName = "tinyauth-session"
var CsrfCookieName = "tinyauth-csrf"
var RedirectCookieName = "tinyauth-redirect"

View File

@@ -581,7 +581,7 @@ func (h *Handlers) OauthUrlHandler(c *gin.Context) {
log.Debug().Msg("Got auth URL")
// Set CSRF cookie
c.SetCookie(h.Config.CsrfCookieName, state, int(time.Hour.Seconds()), "/", "", h.Config.CookieSecure, true)
c.SetCookie("tinyauth-csrf", state, int(time.Hour.Seconds()), "/", "", h.Config.CookieSecure, true)
// Get redirect URI
redirectURI := c.Query("redirect_uri")
@@ -589,7 +589,7 @@ func (h *Handlers) OauthUrlHandler(c *gin.Context) {
// Set redirect cookie if redirect URI is provided
if redirectURI != "" {
log.Debug().Str("redirectURI", redirectURI).Msg("Setting redirect cookie")
c.SetCookie(h.Config.RedirectCookieName, redirectURI, int(time.Hour.Seconds()), "/", "", h.Config.CookieSecure, true)
c.SetCookie("tinyauth-redirect", redirectURI, int(time.Hour.Seconds()), "/", "", h.Config.CookieSecure, true)
}
// Return auth URL
@@ -620,7 +620,7 @@ func (h *Handlers) OauthCallbackHandler(c *gin.Context) {
state := c.Query("state")
// Get CSRF cookie
csrfCookie, err := c.Cookie(h.Config.CsrfCookieName)
csrfCookie, err := c.Cookie("tinyauth-csrf")
if err != nil {
log.Debug().Msg("No CSRF cookie")
@@ -638,7 +638,7 @@ func (h *Handlers) OauthCallbackHandler(c *gin.Context) {
}
// Clean up CSRF cookie
c.SetCookie(h.Config.CsrfCookieName, "", -1, "/", "", h.Config.CookieSecure, true)
c.SetCookie("tinyauth-csrf", "", -1, "/", "", h.Config.CookieSecure, true)
// Get code
code := c.Query("code")
@@ -737,7 +737,7 @@ func (h *Handlers) OauthCallbackHandler(c *gin.Context) {
})
// Check if we have a redirect URI
redirectCookie, err := c.Cookie(h.Config.RedirectCookieName)
redirectCookie, err := c.Cookie("tinyauth-redirect")
if err != nil {
log.Debug().Msg("No redirect cookie")
@@ -762,7 +762,7 @@ func (h *Handlers) OauthCallbackHandler(c *gin.Context) {
}
// Clean up redirect cookie
c.SetCookie(h.Config.RedirectCookieName, "", -1, "/", "", h.Config.CookieSecure, true)
c.SetCookie("tinyauth-redirect", "", -1, "/", "", h.Config.CookieSecure, true)
// Redirect to continue with the redirect URI
c.Redirect(http.StatusPermanentRedirect, fmt.Sprintf("%s/continue?%s", h.Config.AppURL, queries.Encode()))

View File

@@ -48,8 +48,6 @@ type HandlersConfig struct {
ForgotPasswordMessage string
BackgroundImage string
OAuthAutoRedirect string
CsrfCookieName string
RedirectCookieName string
}
// OAuthConfig is the configuration for the providers
@@ -75,15 +73,14 @@ type APIConfig struct {
// AuthConfig is the configuration for the auth service
type AuthConfig struct {
Users Users
OauthWhitelist string
SessionExpiry int
Secret string
CookieSecure bool
Domain string
LoginTimeout int
LoginMaxRetries int
SessionCookieName string
Users Users
OauthWhitelist string
SessionExpiry int
Secret string
CookieSecure bool
Domain string
LoginTimeout int
LoginMaxRetries int
}
// HooksConfig is the configuration for the hooks service

View File

@@ -10,7 +10,6 @@ import (
"tinyauth/internal/constants"
"tinyauth/internal/types"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
)
@@ -345,18 +344,3 @@ func SanitizeHeader(header string) string {
return -1
}, header)
}
// Generate a static identifier from a string
func GenerateIdentifier(str string) string {
// Create a new UUID
uuid := uuid.NewSHA1(uuid.NameSpaceURL, []byte(str))
// Convert the UUID to a string
uuidString := uuid.String()
// Show the UUID
log.Debug().Str("uuid", uuidString).Msg("Generated UUID")
// Convert the UUID to a string
return strings.Split(uuidString, "-")[0]
}