feat: do not show oidc consent screen every time (#989)

This commit is contained in:
Stavros
2026-08-17 02:44:48 +03:00
committed by GitHub
parent 61f65cfaa7
commit 0c47e68c09
26 changed files with 779 additions and 9 deletions
+74
View File
@@ -277,6 +277,80 @@ func TestMemoryStore(t *testing.T) {
assert.NoError(t, err)
},
},
{
description: "Upsert creates a consent for each user+client pair",
run: func(t *testing.T, s repository.Store) {
_, err := s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-a", Scope: "openid profile", CreatedAt: 1,
})
require.NoError(t, err)
_, err = s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-b", Scope: "openid email", CreatedAt: 2,
})
require.NoError(t, err)
consents, err := s.ListOIDCConsents(ctx)
require.NoError(t, err)
assert.Len(t, consents, 2)
gotA, err := s.GetOIDCConsentByUsernameAndClientID(ctx, repository.GetOIDCConsentByUsernameAndClientIDParams{Username: "alice", ClientID: "client-a"})
require.NoError(t, err)
assert.Equal(t, "openid profile", gotA.Scope)
gotB, err := s.GetOIDCConsentByUsernameAndClientID(ctx, repository.GetOIDCConsentByUsernameAndClientIDParams{Username: "alice", ClientID: "client-b"})
require.NoError(t, err)
assert.Equal(t, "openid email", gotB.Scope)
},
},
{
description: "Upsert overwrites the same consent row",
run: func(t *testing.T, s repository.Store) {
_, err := s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-a", Scope: "openid", CreatedAt: 1,
})
require.NoError(t, err)
_, err = s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-a", Scope: "openid email", CreatedAt: 2,
})
require.NoError(t, err)
consents, err := s.ListOIDCConsents(ctx)
require.NoError(t, err)
assert.Len(t, consents, 1)
got, err := s.GetOIDCConsentByUsernameAndClientID(ctx, repository.GetOIDCConsentByUsernameAndClientIDParams{Username: "alice", ClientID: "client-a"})
require.NoError(t, err)
assert.Equal(t, "openid email", got.Scope)
},
},
{
description: "Get consent by username and client not found",
run: func(t *testing.T, s repository.Store) {
_, err := s.GetOIDCConsentByUsernameAndClientID(ctx, repository.GetOIDCConsentByUsernameAndClientIDParams{Username: "alice", ClientID: "client-a"})
assert.ErrorIs(t, err, repository.ErrNotFound)
},
},
{
description: "Delete consent by client id",
run: func(t *testing.T, s repository.Store) {
_, err := s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-a", Scope: "openid", CreatedAt: 1,
})
require.NoError(t, err)
_, err = s.UpsertOIDCConsent(ctx, repository.UpsertOIDCConsentParams{
Username: "alice", ClientID: "client-b", Scope: "openid", CreatedAt: 2,
})
require.NoError(t, err)
require.NoError(t, s.DeleteOIDCConsentByClientID(ctx, "client-a"))
consents, err := s.ListOIDCConsents(ctx)
require.NoError(t, err)
assert.Len(t, consents, 1)
assert.Equal(t, "client-b", consents[0].ClientID)
},
},
}
for _, test := range tests {
@@ -94,3 +94,46 @@ func (s *Store) DeleteExpiredOIDCSessions(_ context.Context, arg repository.Dele
}
return nil
}
func consentKey(username, clientID string) string {
return username + "\x00" + clientID
}
func (s *Store) UpsertOIDCConsent(_ context.Context, arg repository.UpsertOIDCConsentParams) (repository.OidcConsent, error) {
s.mu.Lock()
defer s.mu.Unlock()
oc := repository.OidcConsent(arg)
s.oidcConsents[consentKey(arg.Username, arg.ClientID)] = oc
return oc, nil
}
func (s *Store) GetOIDCConsentByUsernameAndClientID(_ context.Context, arg repository.GetOIDCConsentByUsernameAndClientIDParams) (repository.OidcConsent, error) {
s.mu.RLock()
defer s.mu.RUnlock()
oc, ok := s.oidcConsents[consentKey(arg.Username, arg.ClientID)]
if !ok {
return repository.OidcConsent{}, repository.ErrNotFound
}
return oc, nil
}
func (s *Store) DeleteOIDCConsentByClientID(_ context.Context, clientID string) error {
s.mu.Lock()
defer s.mu.Unlock()
for key, oc := range s.oidcConsents {
if oc.ClientID == clientID {
delete(s.oidcConsents, key)
}
}
return nil
}
func (s *Store) ListOIDCConsents(_ context.Context) ([]repository.OidcConsent, error) {
s.mu.RLock()
defer s.mu.RUnlock()
out := make([]repository.OidcConsent, 0, len(s.oidcConsents))
for _, oc := range s.oidcConsents {
out = append(out, oc)
}
return out, nil
}
+2
View File
@@ -12,6 +12,7 @@ type Store struct {
mu sync.RWMutex
sessions map[string]repository.Session
oidcSessions map[string]repository.OidcSession
oidcConsents map[string]repository.OidcConsent
}
// New returns a new empty in-memory Store.
@@ -19,5 +20,6 @@ func New() repository.Store {
return &Store{
sessions: make(map[string]repository.Session),
oidcSessions: make(map[string]repository.OidcSession),
oidcConsents: make(map[string]repository.OidcConsent),
}
}