mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-04-28 16:38:12 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b231c2958 | |||
| c68a022ed0 |
@@ -0,0 +1,27 @@
|
||||
# AI Usage Policy
|
||||
|
||||
> [!NOTE]
|
||||
> By Tinyauth, we refer to the entire Tinyauth ([tinyauthapp](https://github.com/tinyauthapp)) organization and all of the repositories under it.
|
||||
|
||||
## How we utilize AI in Tinyauth
|
||||
|
||||
In Tinyauth, we see AI as another tool designed to help developers accelerate their work, ***not*** as something that should be doing the development for them. The ways we utilize large language models in Tinyauth are the following:
|
||||
|
||||
- **Pull request reviews**: We utilize [CodeRabbit](https://www.coderabbit.ai/) for reviews in our pull requests which helps us find and fix issues faster, minimizing the time maintainers have to spend reviewing.
|
||||
- **Documentation and Issues**: We use [Dosu](https://dosu.dev/) to help resolve duplicate issues faster and automatically update our documentation based on changes in the code base.
|
||||
- **In-Line Suggestions**: GitHub's [Copilot](https://github.com/features/copilot) is partially used to fill in boilerplate code through in-line suggestions.
|
||||
|
||||
## How we expect the community to use AI
|
||||
|
||||
We expect the Tinyauth community to use AI as a tool for faster development and not as a way to implement entire features through prompts. For this reason, the following guidelines are in place for AI generated content:
|
||||
|
||||
- **All usage must be clearly labeled**: Any content generated by AI must be clearly labeled as such. In the case that a pull request is clearly generated by AI and the author fails to disclose its use, it will be rejected.
|
||||
- **All generated content should be completely understood by the account holder**: The human who utilized the large language model to generate content must have a thorough understanding of it. This includes understanding the resulting output to the full extent and being able to explain it in detail in case it's needed.
|
||||
- **Automated systems are not allowed**: All forms of automated systems that utilize large language models to generate content without human oversight are forbidden. This includes any system that generates content without a human being directly involved in the process like for example with OpenClaw.
|
||||
- **No generated content other than text is allowed**: Images, videos, audio and any other form of content generated by AI other than text is not allowed in Tinyauth.
|
||||
- **AI pull requests are not guaranteed to be accepted or prioritized**: Any pull request that contains AI generated content is not guaranteed to be accepted and/or prioritized. The maintainers are responsible for reviewing all pull requests and determining whether or not they meet the standards of the project. AI generated content will be reviewed with the same standards as any other content, and may be rejected if it does not meet those standards.
|
||||
- **Large generated pull requests will be rejected**: Any pull request that contains a large amount of generated content will be rejected. This is because it is difficult for the maintainers to review and verify large amounts of generated content.
|
||||
|
||||
## Tinyauth is developed by humans, for humans
|
||||
|
||||
Please remember that Tinyauth is developed by humans. While AI can be a useful tool for **assisting** in the development process, it should not be used in place of the human brain. Moving forward, we are committed to ensuring that most, if not all the content in Tinyauth is created and reviewed by humans, and that AI is only used as a tool to assist in the development process.
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
Contributing to Tinyauth is straightforward. Follow the steps below to set up a development server.
|
||||
|
||||
> [!NOTE]
|
||||
> If you are using large language models to contribute to the project, please ensure that you have read and understood the [AI Policy](AI_POLICY.md).
|
||||
|
||||
## Requirements
|
||||
|
||||
- Bun
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@ It is recommended to use the [latest](https://github.com/tinyauthapp/tinyauth/re
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Due to the nature of this app, it needs to be secure. If you discover any security issues or vulnerabilities in the app please contact me as soon as possible at <steve@doesmycode.work>. Please do not use the issues section to report security issues as I won't be able to patch them in time and they may get exploited by malicious actors.
|
||||
Due to the nature of this app, it needs to be secure. If you discover any security issues or vulnerabilities in the app please contact me as soon as possible at <security@tinyauth.app>. Please do not use the issues section to report security issues as I won't be able to patch them in time and they may get exploited by malicious actors.
|
||||
|
||||
@@ -57,16 +57,6 @@ export default defineConfig({
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/robots.txt/, ""),
|
||||
},
|
||||
"/authorize": {
|
||||
target: "http://tinyauth-backend:3000/authorize",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/authorize/, ""),
|
||||
bypass: (req) => {
|
||||
if (req.method === "GET") {
|
||||
return "/index.html";
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
allowedHosts: true,
|
||||
},
|
||||
|
||||
@@ -22,7 +22,7 @@ require (
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
gotest.tools/v3 v3.5.2
|
||||
modernc.org/sqlite v1.49.1
|
||||
modernc.org/sqlite v1.50.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -351,8 +351,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.49.1 h1:dYGHTKcX1sJ+EQDnUzvz4TJ5GbuvhNJa8Fg6ElGx73U=
|
||||
modernc.org/sqlite v1.49.1/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew=
|
||||
modernc.org/sqlite v1.50.0 h1:eMowQSWLK0MeiQTdmz3lqoF5dqclujdlIKeJA11+7oM=
|
||||
modernc.org/sqlite v1.50.0/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
@@ -87,7 +87,7 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
|
||||
|
||||
oauthController.SetupRoutes()
|
||||
|
||||
oidcController := controller.NewOIDCController(controller.OIDCControllerConfig{}, app.services.oidcService, apiRouter, engine)
|
||||
oidcController := controller.NewOIDCController(controller.OIDCControllerConfig{}, app.services.oidcService, apiRouter)
|
||||
|
||||
oidcController.SetupRoutes()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package controller
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -22,7 +21,6 @@ type OIDCController struct {
|
||||
config OIDCControllerConfig
|
||||
router *gin.RouterGroup
|
||||
oidc *service.OIDCService
|
||||
engine *gin.Engine
|
||||
}
|
||||
|
||||
type AuthorizeCallback struct {
|
||||
@@ -59,12 +57,11 @@ type ClientCredentials struct {
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup, engine *gin.Engine) *OIDCController {
|
||||
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup) *OIDCController {
|
||||
return &OIDCController{
|
||||
config: config,
|
||||
oidc: oidcService,
|
||||
router: router,
|
||||
engine: engine,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +72,6 @@ func (controller *OIDCController) SetupRoutes() {
|
||||
oidcGroup.POST("/token", controller.Token)
|
||||
oidcGroup.GET("/userinfo", controller.Userinfo)
|
||||
oidcGroup.POST("/userinfo", controller.Userinfo)
|
||||
controller.engine.POST("/authorize", controller.AuthorizePseudoPost)
|
||||
}
|
||||
|
||||
func (controller *OIDCController) GetClientInfo(c *gin.Context) {
|
||||
@@ -199,18 +195,6 @@ func (controller *OIDCController) Authorize(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// Pseudo handler that will just redirect to get in frontend then back to backend
|
||||
func (controller *OIDCController) AuthorizePseudoPost(c *gin.Context) {
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
tlog.App.Error().Err(err).Msg("Failed to read request body")
|
||||
c.Redirect(http.StatusFound, fmt.Sprintf("%s/authorize", controller.oidc.GetIssuer()))
|
||||
return
|
||||
}
|
||||
redirectUrl := fmt.Sprintf("%s/authorize?%s", controller.oidc.GetIssuer(), body)
|
||||
c.Redirect(http.StatusFound, redirectUrl)
|
||||
}
|
||||
|
||||
func (controller *OIDCController) Token(c *gin.Context) {
|
||||
if !controller.oidc.IsConfigured() {
|
||||
tlog.App.Warn().Msg("OIDC not configured")
|
||||
|
||||
@@ -12,14 +12,14 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
|
||||
"github.com/tinyauthapp/tinyauth/internal/config"
|
||||
"github.com/tinyauthapp/tinyauth/internal/controller"
|
||||
"github.com/tinyauthapp/tinyauth/internal/repository"
|
||||
"github.com/tinyauthapp/tinyauth/internal/service"
|
||||
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOIDCController(t *testing.T) {
|
||||
@@ -846,34 +846,6 @@ func TestOIDCController(t *testing.T) {
|
||||
assert.Equal(t, "invalid_grant", res["error"])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Test authorize request with POST method",
|
||||
middlewares: []gin.HandlerFunc{
|
||||
simpleCtx,
|
||||
},
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
body := service.AuthorizeRequest{
|
||||
Scope: "openid",
|
||||
ResponseType: "code",
|
||||
ClientID: "some-client-id",
|
||||
RedirectURI: "https://test.example.com/callback",
|
||||
State: "some-state",
|
||||
Nonce: "some-nonce",
|
||||
CodeChallenge: "some-challenge",
|
||||
CodeChallengeMethod: "plain",
|
||||
}
|
||||
queries, err := query.Values(body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest("POST", "/authorize", strings.NewReader(string(queries.Encode())))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
router.ServeHTTP(recorder, req)
|
||||
assert.Equal(t, 302, recorder.Code)
|
||||
location := recorder.Header().Get("Location")
|
||||
assert.NotEmpty(t, location)
|
||||
assert.Equal(t, "https://tinyauth.example.com/authorize?client_id=some-client-id&code_challenge=some-challenge&code_challenge_method=plain&nonce=some-nonce&redirect_uri=https%3A%2F%2Ftest.example.com%2Fcallback&response_type=code&scope=openid&state=some-state", location)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app := bootstrap.NewBootstrapApp(config.Config{})
|
||||
@@ -897,7 +869,7 @@ func TestOIDCController(t *testing.T) {
|
||||
group := router.Group("/api")
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
oidcController := controller.NewOIDCController(controllerCfg, oidcService, group, router)
|
||||
oidcController := controller.NewOIDCController(controllerCfg, oidcService, group)
|
||||
oidcController.SetupRoutes()
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
@@ -39,7 +39,6 @@ func (m *UIMiddleware) Init() error {
|
||||
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
||||
method := c.Request.Method
|
||||
|
||||
tlog.App.Debug().Str("path", path).Msg("path")
|
||||
|
||||
@@ -53,12 +52,6 @@ func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||
c.Writer.Write([]byte("User-agent: *\nDisallow: /\n"))
|
||||
return
|
||||
default:
|
||||
// For OIDC post authentication, we need to redirect the POST to /authorize to the backend
|
||||
if method == http.MethodPost && strings.HasPrefix(path, "authorize") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
_, err := fs.Stat(m.uiFs, path)
|
||||
|
||||
// Enough for one authentication flow
|
||||
|
||||
@@ -100,15 +100,14 @@ type TokenResponse struct {
|
||||
}
|
||||
|
||||
type AuthorizeRequest struct {
|
||||
Scope string `json:"scope" binding:"required" url:"scope"`
|
||||
ResponseType string `json:"response_type" binding:"required" url:"response_type"`
|
||||
ClientID string `json:"client_id" binding:"required" url:"client_id"`
|
||||
RedirectURI string `json:"redirect_uri" binding:"required" url:"redirect_uri"`
|
||||
State string `json:"state" url:"state"`
|
||||
Nonce string `json:"nonce" url:"nonce"`
|
||||
CodeChallenge string `json:"code_challenge" url:"code_challenge"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method" url:"code_challenge_method"`
|
||||
Request string `json:"request" url:"request"`
|
||||
Scope string `json:"scope" binding:"required"`
|
||||
ResponseType string `json:"response_type" binding:"required"`
|
||||
ClientID string `json:"client_id" binding:"required"`
|
||||
RedirectURI string `json:"redirect_uri" binding:"required"`
|
||||
State string `json:"state"`
|
||||
Nonce string `json:"nonce"`
|
||||
CodeChallenge string `json:"code_challenge"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method"`
|
||||
}
|
||||
|
||||
type OIDCServiceConfig struct {
|
||||
|
||||
Reference in New Issue
Block a user