Skip to content

Commit 54d7dfe

Browse files
authored
feat(oidc): allow trusted clients to skip consent (#1159)
1 parent 4ecec9d commit 54d7dfe

5 files changed

Lines changed: 45 additions & 0 deletions

File tree

‎.env.example‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRET=
200200
TINYAUTH_OIDC_CLIENTS_name_CLIENTSECRETFILE=
201201
# List of trusted redirect URIs.
202202
TINYAUTH_OIDC_CLIENTS_name_TRUSTEDREDIRECTURIS=
203+
# Skip the consent screen for this trusted OIDC client.
204+
TINYAUTH_OIDC_CLIENTS_name_TRUSTED=false
203205
# Client name in UI.
204206
TINYAUTH_OIDC_CLIENTS_name_NAME=
205207

‎internal/controller/oidc_controller.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,14 @@ func (controller *OIDCController) skipConsent(c *gin.Context) {
327327
return
328328
}
329329

330+
client, ok := controller.oidc.GetClient(authorizeReq.ClientID)
331+
if ok && client.Trusted {
332+
c.JSON(200, SkipConsentResponse{
333+
SkipConsent: true,
334+
})
335+
return
336+
}
337+
330338
consent, err := controller.oidc.GetOIDCConsent(c, userContext.GetUsername(), authorizeReq.ClientID)
331339

332340
if err != nil || consent == nil {

‎internal/controller/oidc_controller_test.go‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,33 @@ func TestOIDCController(t *testing.T) {
351351
assert.False(t, res.SkipConsent)
352352
},
353353
},
354+
{
355+
description: "Skip consent returns true for a trusted client without prior consent",
356+
middlewares: []gin.HandlerFunc{authedUser},
357+
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
358+
require.NoError(t, store.DeleteOIDCConsentByClientID(ctx, "trusted-client-id"))
359+
360+
ticket := oidcService.CreateAuthorizeRequestTicket(service.AuthorizeRequest{
361+
Scope: "openid profile",
362+
ResponseType: "code",
363+
ClientID: "trusted-client-id",
364+
RedirectURI: "https://trusted.example.com/callback",
365+
})
366+
367+
req := httptest.NewRequest("GET", "/api/oidc/skip-consent?oidc_ticket="+url.QueryEscape(ticket), nil)
368+
router.ServeHTTP(recorder, req)
369+
370+
assert.Equal(t, http.StatusOK, recorder.Code)
371+
372+
var res SkipConsentResponse
373+
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &res))
374+
assert.True(t, res.SkipConsent)
375+
376+
// skip-consent is only a check; it must not consume the ticket.
377+
_, ok := oidcService.GetAuthorizeRequestByTicket(ticket)
378+
assert.True(t, ok)
379+
},
380+
},
354381
{
355382
description: "Skip consent returns false when a new scope is requested",
356383
middlewares: []gin.HandlerFunc{authedUser},

‎internal/model/config.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ type OIDCClientConfig struct {
290290
ClientSecret string `description:"OIDC client secret." yaml:"clientSecret,omitempty"`
291291
ClientSecretFile string `description:"Path to the file containing the OIDC client secret." yaml:"clientSecretFile,omitempty"`
292292
TrustedRedirectURIs []string `description:"List of trusted redirect URIs." yaml:"trustedRedirectUris,omitempty"`
293+
Trusted bool `description:"Skip the consent screen for this trusted OIDC client." yaml:"trusted,omitempty"`
293294
Name string `description:"Client name in UI." yaml:"name,omitempty"`
294295
}
295296

‎internal/test/test.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ func CreateTestConfigs(t *testing.T) (model.Config, model.RuntimeConfig) {
3232
TrustedRedirectURIs: []string{"https://test.example.com/callback"},
3333
Name: "Test Client",
3434
},
35+
"trusted-test": {
36+
ClientID: "trusted-client-id",
37+
ClientSecret: "trusted-client-secret",
38+
TrustedRedirectURIs: []string{"https://trusted.example.com/callback"},
39+
Trusted: true,
40+
Name: "Trusted Test Client",
41+
},
3542
},
3643
PrivateKeyPath: filepath.Join(tempDir, "key.pem"),
3744
PublicKeyPath: filepath.Join(tempDir, "key.pub"),

0 commit comments

Comments
 (0)