From a6e74751539f5a9f0fa2d82a2d912009dbfe2d42 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 26 Mar 2026 16:31:54 +0100 Subject: [PATCH] feat: add OAuth client validation and PKCE verification Add redirect URI validation that allowlists vikunja-* custom protocol schemes, rejecting http/https and dangerous schemes like javascript:. Add PKCE S256 verification following RFC 7636. --- pkg/modules/auth/oauth2server/client.go | 35 +++++++++++++++++++++++++ pkg/modules/auth/oauth2server/pkce.go | 34 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 pkg/modules/auth/oauth2server/client.go create mode 100644 pkg/modules/auth/oauth2server/pkce.go diff --git a/pkg/modules/auth/oauth2server/client.go b/pkg/modules/auth/oauth2server/client.go new file mode 100644 index 000000000..44e381958 --- /dev/null +++ b/pkg/modules/auth/oauth2server/client.go @@ -0,0 +1,35 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package oauth2server + +import ( + "net/url" + "strings" +) + +// ValidateRedirectURI checks that the redirect_uri uses a scheme starting with +// "vikunja-". This allowlists only Vikunja native app schemes (e.g. +// vikunja-flutter://callback) and rejects dangerous schemes like javascript:, +// data:, http:, https:, etc. +func ValidateRedirectURI(redirectURI string) bool { + u, err := url.Parse(redirectURI) + if err != nil || u.Scheme == "" { + return false + } + + return strings.HasPrefix(u.Scheme, "vikunja-") +} diff --git a/pkg/modules/auth/oauth2server/pkce.go b/pkg/modules/auth/oauth2server/pkce.go new file mode 100644 index 000000000..6f88b0fb1 --- /dev/null +++ b/pkg/modules/auth/oauth2server/pkce.go @@ -0,0 +1,34 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package oauth2server + +import ( + "crypto/sha256" + "encoding/base64" +) + +// VerifyPKCE verifies a PKCE code_verifier against a stored code_challenge using S256. +// S256: BASE64URL(SHA256(code_verifier)) == code_challenge +func VerifyPKCE(codeVerifier, codeChallenge, codeChallengeMethod string) bool { + if codeChallengeMethod != "S256" { + return false + } + + h := sha256.Sum256([]byte(codeVerifier)) + computed := base64.RawURLEncoding.EncodeToString(h[:]) + return computed == codeChallenge +}