diff --git a/backend/internal/dto/oidc_dto.go b/backend/internal/dto/oidc_dto.go index e2e8a97..1e534dc 100644 --- a/backend/internal/dto/oidc_dto.go +++ b/backend/internal/dto/oidc_dto.go @@ -10,6 +10,7 @@ type OidcClientDto struct { PublicOidcClientDto CallbackURLs []string `json:"callbackURLs"` IsPublic bool `json:"isPublic"` + PkceEnabled bool `json:"pkceEnabled"` CreatedBy UserDto `json:"createdBy"` } @@ -17,6 +18,7 @@ type OidcClientCreateDto struct { Name string `json:"name" binding:"required,max=50"` CallbackURLs []string `json:"callbackURLs" binding:"required,urlList"` IsPublic bool `json:"isPublic"` + PkceEnabled bool `json:"pkceEnabled"` } type AuthorizeOidcClientRequestDto struct { diff --git a/backend/internal/model/oidc.go b/backend/internal/model/oidc.go index bf0904f..12e4713 100644 --- a/backend/internal/model/oidc.go +++ b/backend/internal/model/oidc.go @@ -42,6 +42,7 @@ type OidcClient struct { ImageType *string HasLogo bool `gorm:"-"` IsPublic bool + PkceEnabled bool CreatedByID string CreatedBy User diff --git a/backend/internal/service/oidc_service.go b/backend/internal/service/oidc_service.go index 0ddbdfd..c49833b 100644 --- a/backend/internal/service/oidc_service.go +++ b/backend/internal/service/oidc_service.go @@ -131,8 +131,8 @@ func (s *OidcService) CreateTokens(code, grantType, clientID, clientSecret, code return "", "", &common.OidcInvalidAuthorizationCodeError{} } - // If the client is public, the code verifier must match the code challenge - if client.IsPublic { + // If the client is public or PKCE is enabled, the code verifier must match the code challenge + if client.IsPublic || client.PkceEnabled { if !s.validateCodeVerifier(codeVerifier, *authorizationCodeMetaData.CodeChallenge, *authorizationCodeMetaData.CodeChallengeMethodSha256) { return "", "", &common.OidcInvalidCodeVerifierError{} } @@ -189,6 +189,8 @@ func (s *OidcService) CreateClient(input dto.OidcClientCreateDto, userID string) Name: input.Name, CallbackURLs: input.CallbackURLs, CreatedByID: userID, + IsPublic: input.IsPublic, + PkceEnabled: input.IsPublic || input.PkceEnabled, } if err := s.db.Create(&client).Error; err != nil { @@ -207,6 +209,7 @@ func (s *OidcService) UpdateClient(clientID string, input dto.OidcClientCreateDt client.Name = input.Name client.CallbackURLs = input.CallbackURLs client.IsPublic = input.IsPublic + client.PkceEnabled = input.IsPublic || input.PkceEnabled if err := s.db.Save(&client).Error; err != nil { return model.OidcClient{}, err @@ -406,6 +409,10 @@ func (s *OidcService) createAuthorizationCode(clientID string, userID string, sc } func (s *OidcService) validateCodeVerifier(codeVerifier, codeChallenge string, codeChallengeMethodSha256 bool) bool { + if codeVerifier == "" || codeChallenge == "" { + return false + } + if !codeChallengeMethodSha256 { return codeVerifier == codeChallenge } diff --git a/backend/resources/migrations/postgres/20250103145821_pkce_column.down.sql b/backend/resources/migrations/postgres/20250103145821_pkce_column.down.sql new file mode 100644 index 0000000..dc517ca --- /dev/null +++ b/backend/resources/migrations/postgres/20250103145821_pkce_column.down.sql @@ -0,0 +1 @@ +ALTER TABLE oidc_clients DROP COLUMN pkce_enabled; \ No newline at end of file diff --git a/backend/resources/migrations/postgres/20250103145821_pkce_column.up.sql b/backend/resources/migrations/postgres/20250103145821_pkce_column.up.sql new file mode 100644 index 0000000..89a5b53 --- /dev/null +++ b/backend/resources/migrations/postgres/20250103145821_pkce_column.up.sql @@ -0,0 +1 @@ +ALTER TABLE oidc_clients ADD COLUMN pkce_enabled BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/backend/resources/migrations/sqlite/20250103145821_pkce_column.down.sql b/backend/resources/migrations/sqlite/20250103145821_pkce_column.down.sql new file mode 100644 index 0000000..dc517ca --- /dev/null +++ b/backend/resources/migrations/sqlite/20250103145821_pkce_column.down.sql @@ -0,0 +1 @@ +ALTER TABLE oidc_clients DROP COLUMN pkce_enabled; \ No newline at end of file diff --git a/backend/resources/migrations/sqlite/20250103145821_pkce_column.up.sql b/backend/resources/migrations/sqlite/20250103145821_pkce_column.up.sql new file mode 100644 index 0000000..89a5b53 --- /dev/null +++ b/backend/resources/migrations/sqlite/20250103145821_pkce_column.up.sql @@ -0,0 +1 @@ +ALTER TABLE oidc_clients ADD COLUMN pkce_enabled BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/frontend/src/lib/components/checkbox-with-label.svelte b/frontend/src/lib/components/checkbox-with-label.svelte index 1117655..571ff02 100644 --- a/frontend/src/lib/components/checkbox-with-label.svelte +++ b/frontend/src/lib/components/checkbox-with-label.svelte @@ -6,12 +6,26 @@ id, checked = $bindable(), label, - description - }: { id: string; checked: boolean; label: string; description?: string } = $props(); + description, + disabled = false, + onCheckedChange + }: { + id: string; + checked: boolean; + label: string; + description?: string; + disabled?: boolean; + onCheckedChange?: (checked: boolean) => void; + } = $props();