mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-03-02 12:52:02 +00:00
Compare commits
6 Commits
v5.0.0-alp
...
ce8493239e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce8493239e | ||
|
|
71fe73cca0 | ||
|
|
0fe89ae4e4 | ||
|
|
22c4c262ea | ||
|
|
baf4798665 | ||
|
|
bea680edec |
2
Makefile
2
Makefile
@@ -10,7 +10,7 @@ BUILD_TIMESTAMP := $(shell date '+%Y-%m-%dT%H:%M:%S')
|
|||||||
BIN_NAME := tinyauth-$(GOARCH)
|
BIN_NAME := tinyauth-$(GOARCH)
|
||||||
|
|
||||||
# Development vars
|
# Development vars
|
||||||
DEV_COMPOSE := $(shell test -f "docker-compose.test.yml" && echo "docker-compose.test.yml" || echo "docker-compose.yml" )
|
DEV_COMPOSE := $(shell test -f "docker-compose.test.yml" && echo "docker-compose.test.yml" || echo "docker-compose.dev.yml" )
|
||||||
PROD_COMPOSE := $(shell test -f "docker-compose.test.prod.yml" && echo "docker-compose.test.prod.yml" || echo "docker-compose.example.yml" )
|
PROD_COMPOSE := $(shell test -f "docker-compose.test.prod.yml" && echo "docker-compose.test.prod.yml" || echo "docker-compose.example.yml" )
|
||||||
|
|
||||||
# Deps
|
# Deps
|
||||||
|
|||||||
@@ -30,15 +30,9 @@ func healthcheckCmd() *cli.Command {
|
|||||||
|
|
||||||
appUrl := "http://127.0.0.1:3000"
|
appUrl := "http://127.0.0.1:3000"
|
||||||
|
|
||||||
appUrlEnv := os.Getenv("TINYAUTH_APPURL")
|
|
||||||
srvAddr := os.Getenv("TINYAUTH_SERVER_ADDRESS")
|
srvAddr := os.Getenv("TINYAUTH_SERVER_ADDRESS")
|
||||||
srvPort := os.Getenv("TINYAUTH_SERVER_PORT")
|
srvPort := os.Getenv("TINYAUTH_SERVER_PORT")
|
||||||
|
|
||||||
if appUrlEnv != "" {
|
|
||||||
appUrl = appUrlEnv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local-direct connection is preferred over the public app URL
|
|
||||||
if srvAddr != "" && srvPort != "" {
|
if srvAddr != "" && srvPort != "" {
|
||||||
appUrl = fmt.Sprintf("http://%s:%s", srvAddr, srvPort)
|
appUrl = fmt.Sprintf("http://%s:%s", srvAddr, srvPort)
|
||||||
}
|
}
|
||||||
@@ -48,7 +42,7 @@ func healthcheckCmd() *cli.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if appUrl == "" {
|
if appUrl == "" {
|
||||||
return errors.New("TINYAUTH_APPURL is not set and no argument was provided")
|
return errors.New("Could not determine app URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
tlog.App.Info().Str("app_url", appUrl).Msg("Performing health check")
|
tlog.App.Info().Str("app_url", appUrl).Msg("Performing health check")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ services:
|
|||||||
image: traefik/whoami:latest
|
image: traefik/whoami:latest
|
||||||
labels:
|
labels:
|
||||||
traefik.enable: true
|
traefik.enable: true
|
||||||
traefik.http.routers.whoami.rule: Host(`whoami.example.com`)
|
traefik.http.routers.whoami.rule: Host(`whoami.127.0.0.1.sslip.io`)
|
||||||
traefik.http.routers.whoami.middlewares: tinyauth
|
traefik.http.routers.whoami.middlewares: tinyauth
|
||||||
|
|
||||||
tinyauth-frontend:
|
tinyauth-frontend:
|
||||||
@@ -27,7 +27,7 @@ services:
|
|||||||
- 5173:5173
|
- 5173:5173
|
||||||
labels:
|
labels:
|
||||||
traefik.enable: true
|
traefik.enable: true
|
||||||
traefik.http.routers.tinyauth.rule: Host(`tinyauth.example.com`)
|
traefik.http.routers.tinyauth.rule: Host(`tinyauth.127.0.0.1.sslip.io`)
|
||||||
|
|
||||||
tinyauth-backend:
|
tinyauth-backend:
|
||||||
container_name: tinyauth-backend
|
container_name: tinyauth-backend
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export const DomainWarning = (props: Props) => {
|
|||||||
i18nKey="domainWarningSubtitle"
|
i18nKey="domainWarningSubtitle"
|
||||||
values={{ appUrl, currentUrl }}
|
values={{ appUrl, currentUrl }}
|
||||||
components={{ code: <code /> }}
|
components={{ code: <code /> }}
|
||||||
|
shouldUnescape={true}
|
||||||
/>
|
/>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export const ContinuePage = () => {
|
|||||||
code: <code />,
|
code: <code />,
|
||||||
}}
|
}}
|
||||||
values={{ cookieDomain }}
|
values={{ cookieDomain }}
|
||||||
|
shouldUnescape={true}
|
||||||
/>
|
/>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export const LogoutPage = () => {
|
|||||||
username: email,
|
username: email,
|
||||||
provider: oauthName,
|
provider: oauthName,
|
||||||
}}
|
}}
|
||||||
|
shouldUnescape={true}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Trans
|
<Trans
|
||||||
@@ -78,6 +79,7 @@ export const LogoutPage = () => {
|
|||||||
values={{
|
values={{
|
||||||
username,
|
username,
|
||||||
}}
|
}}
|
||||||
|
shouldUnescape={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ type OIDCClientConfig struct {
|
|||||||
ClientID string `description:"OIDC client ID." yaml:"clientId"`
|
ClientID string `description:"OIDC client ID." yaml:"clientId"`
|
||||||
ClientSecret string `description:"OIDC client secret." yaml:"clientSecret"`
|
ClientSecret string `description:"OIDC client secret." yaml:"clientSecret"`
|
||||||
ClientSecretFile string `description:"Path to the file containing the OIDC client secret." yaml:"clientSecretFile"`
|
ClientSecretFile string `description:"Path to the file containing the OIDC client secret." yaml:"clientSecretFile"`
|
||||||
TrustedRedirectURIs []string `description:"List of trusted redirect URLs." yaml:"trustedRedirectUrls"`
|
TrustedRedirectURIs []string `description:"List of trusted redirect URIs." yaml:"trustedRedirectUris"`
|
||||||
Name string `description:"Client name in UI." yaml:"name"`
|
Name string `description:"Client name in UI." yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ type TokenRequest struct {
|
|||||||
Code string `form:"code" url:"code"`
|
Code string `form:"code" url:"code"`
|
||||||
RedirectURI string `form:"redirect_uri" url:"redirect_uri"`
|
RedirectURI string `form:"redirect_uri" url:"redirect_uri"`
|
||||||
RefreshToken string `form:"refresh_token" url:"refresh_token"`
|
RefreshToken string `form:"refresh_token" url:"refresh_token"`
|
||||||
|
ClientSecret string `form:"client_secret" url:"client_secret"`
|
||||||
|
ClientID string `form:"client_id" url:"client_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallbackError struct {
|
type CallbackError struct {
|
||||||
@@ -49,6 +51,11 @@ type ClientRequest struct {
|
|||||||
ClientID string `uri:"id" binding:"required"`
|
ClientID string `uri:"id" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ClientCredentials struct {
|
||||||
|
ClientID string
|
||||||
|
ClientSecret string
|
||||||
|
}
|
||||||
|
|
||||||
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup) *OIDCController {
|
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup) *OIDCController {
|
||||||
return &OIDCController{
|
return &OIDCController{
|
||||||
config: config,
|
config: config,
|
||||||
@@ -210,29 +217,45 @@ func (controller *OIDCController) Token(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rclientId, rclientSecret, ok := c.Request.BasicAuth()
|
// First we try form values
|
||||||
|
creds := ClientCredentials{
|
||||||
if !ok {
|
ClientID: req.ClientID,
|
||||||
tlog.App.Error().Msg("Missing authorization header")
|
ClientSecret: req.ClientSecret,
|
||||||
c.Header("www-authenticate", "basic")
|
|
||||||
c.JSON(401, gin.H{
|
|
||||||
"error": "invalid_client",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client, ok := controller.oidc.GetClient(rclientId)
|
// If it fails, we try basic auth
|
||||||
|
if creds.ClientID == "" || creds.ClientSecret == "" {
|
||||||
|
tlog.App.Debug().Msg("Tried form values and they are empty, trying basic auth")
|
||||||
|
|
||||||
|
clientId, clientSecret, ok := c.Request.BasicAuth()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
tlog.App.Error().Msg("Missing authorization header")
|
||||||
|
c.Header("www-authenticate", "basic")
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"error": "invalid_client",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
creds.ClientID = clientId
|
||||||
|
creds.ClientSecret = clientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
// END - we don't support other authentication methods
|
||||||
|
|
||||||
|
client, ok := controller.oidc.GetClient(creds.ClientID)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
tlog.App.Warn().Str("client_id", rclientId).Msg("Client not found")
|
tlog.App.Warn().Str("client_id", creds.ClientID).Msg("Client not found")
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"error": "invalid_client",
|
"error": "invalid_client",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.ClientSecret != rclientSecret {
|
if client.ClientSecret != creds.ClientSecret {
|
||||||
tlog.App.Warn().Str("client_id", rclientId).Msg("Invalid client secret")
|
tlog.App.Warn().Str("client_id", creds.ClientID).Msg("Invalid client secret")
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"error": "invalid_client",
|
"error": "invalid_client",
|
||||||
})
|
})
|
||||||
@@ -286,7 +309,7 @@ func (controller *OIDCController) Token(c *gin.Context) {
|
|||||||
|
|
||||||
tokenResponse = tokenRes
|
tokenResponse = tokenRes
|
||||||
case "refresh_token":
|
case "refresh_token":
|
||||||
tokenRes, err := controller.oidc.RefreshAccessToken(c, req.RefreshToken, rclientId)
|
tokenRes, err := controller.oidc.RefreshAccessToken(c, req.RefreshToken, creds.ClientID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, service.ErrTokenExpired) {
|
if errors.Is(err, service.ErrTokenExpired) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context
|
|||||||
GrantTypesSupported: service.SupportedGrantTypes,
|
GrantTypesSupported: service.SupportedGrantTypes,
|
||||||
SubjectTypesSupported: []string{"pairwise"},
|
SubjectTypesSupported: []string{"pairwise"},
|
||||||
IDTokenSigningAlgValuesSupported: []string{"RS256"},
|
IDTokenSigningAlgValuesSupported: []string{"RS256"},
|
||||||
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"},
|
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic", "client_secret_post"},
|
||||||
ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "groups"},
|
ClaimsSupported: []string{"sub", "updated_at", "name", "preferred_username", "email", "groups"},
|
||||||
ServiceDocumentation: "https://tinyauth.app/docs/reference/openid",
|
ServiceDocumentation: "https://tinyauth.app/docs/reference/openid",
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user