[PR #2308] feat: OAuth 2.0 authorization server for Flutter app #4056

Open
opened 2026-03-22 15:00:24 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/go-vikunja/vikunja/pull/2308
Author: @kolaente
Created: 2/26/2026
Status: 🔄 Open

Base: mainHead: feat-oauth-server


📝 Commits (10+)

  • 0f4f373 feat: add OAuthCode model for OAuth 2.0 authorization codes
  • 9811b54 feat: add database migration for oauth_codes table
  • 634c04d feat: add OAuth server error types
  • 0cce26e feat: add OAuth server client config and PKCE verification
  • eb83aa7 feat: register OAuth authorize and token routes
  • 862d56e feat: handle OAuth redirect parameter after login
  • 10ac330 test: add web tests for OAuth 2.0 authorization flow
  • 079729b chore: lint fixes for OAuth server implementation
  • a806531 fix: check disabled account status in authorization code grant
  • 38d5505 fix: use ServicePublicURL instead of Host header in buildAuthorizeURL

📊 Changes

18 files changed (+1434 additions, -6 deletions)

View changed files

📝 frontend/src/views/user/Login.vue (+19 -1)
📝 frontend/src/views/user/OpenIdAuth.vue (+18 -1)
frontend/tests/e2e/user/oauth-authorize.spec.ts (+135 -0)
pkg/db/fixtures/oauth_codes.yml (+2 -0)
pkg/migration/20260226172819.go (+51 -0)
📝 pkg/models/error.go (+179 -0)
📝 pkg/models/models.go (+1 -0)
pkg/models/oauth_codes.go (+99 -0)
📝 pkg/models/setup_tests.go (+1 -0)
📝 pkg/modules/auth/auth.go (+5 -4)
pkg/modules/auth/oauth2server/authorize.go (+164 -0)
pkg/modules/auth/oauth2server/client.go (+44 -0)
pkg/modules/auth/oauth2server/client_test.go (+35 -0)
pkg/modules/auth/oauth2server/pkce.go (+34 -0)
pkg/modules/auth/oauth2server/pkce_test.go (+51 -0)
pkg/modules/auth/oauth2server/token.go (+222 -0)
📝 pkg/routes/routes.go (+9 -0)
pkg/webtests/oauth2_test.go (+365 -0)

📄 Description

Summary

This PR implements an OAuth 2.0 authorization server to enable the Flutter app to authenticate using the authorization code flow with PKCE.

Changes

Backend

  • OAuthCode model (pkg/models/oauth_codes.go) - Stores authorization codes with PKCE challenge, user ID, and expiry
  • Database migration (pkg/migration/20260226172819.go) - Creates oauth_codes table
  • OAuth error types (pkg/models/error.go) - Added 7 error types (17001-17007) for OAuth-specific errors
  • OAuth2 server package (pkg/modules/auth/oauth2server/):
    • client.go - Client validation (Flutter client ID: vikunja-flutter, redirect URI: vikunja://callback)
    • pkce.go - PKCE S256 verification
    • authorize.go - Authorization endpoint handler (GET /api/v1/oauth/authorize)
    • token.go - Token endpoint handler (POST /api/v1/oauth/token) with authorization_code and refresh_token grant types
  • Route registration (pkg/routes/routes.go) - Registered OAuth endpoints

Frontend

  • Login.vue and OpenIdAuth.vue - Handle OAuth redirect parameter after successful login

Tests

  • Unit tests for client validation and PKCE verification
  • Web tests (pkg/webtests/oauth2_test.go) - 11 integration test cases covering the full OAuth flow

OAuth Flow

  1. Flutter app opens /api/v1/oauth/authorize with client_id, redirect_uri, response_type, code_challenge, code_challenge_method
  2. If not logged in, redirects to login page with return URL
  3. After login, redirects back to authorize endpoint
  4. Authorize endpoint creates code and redirects to vikunja://callback with code
  5. Flutter app exchanges code for tokens via POST /api/v1/oauth/token
  6. Refresh tokens can be exchanged for new access/refresh token pairs

Security Features

  • PKCE (S256) required for all authorization requests
  • Single-use authorization codes (deleted on use)
  • 10-minute code expiry
  • Refresh token rotation
  • Same-origin validation for OAuth redirects in frontend

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/go-vikunja/vikunja/pull/2308 **Author:** [@kolaente](https://github.com/kolaente) **Created:** 2/26/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat-oauth-server` --- ### 📝 Commits (10+) - [`0f4f373`](https://github.com/go-vikunja/vikunja/commit/0f4f373de759660c5ab0ce01ebd76a48b32db646) feat: add OAuthCode model for OAuth 2.0 authorization codes - [`9811b54`](https://github.com/go-vikunja/vikunja/commit/9811b54625481c03c7bc4108eeabcbaa488b3d34) feat: add database migration for oauth_codes table - [`634c04d`](https://github.com/go-vikunja/vikunja/commit/634c04d079e900aca9f48ffe5dfeeff8fae4f9ae) feat: add OAuth server error types - [`0cce26e`](https://github.com/go-vikunja/vikunja/commit/0cce26ededfd5c8dd649abe465e0b8320278442b) feat: add OAuth server client config and PKCE verification - [`eb83aa7`](https://github.com/go-vikunja/vikunja/commit/eb83aa76c9ed926105f58c62e5c8e4cae3d13dfe) feat: register OAuth authorize and token routes - [`862d56e`](https://github.com/go-vikunja/vikunja/commit/862d56e19e8f3a4f8b69e96777f621a3a1f8e254) feat: handle OAuth redirect parameter after login - [`10ac330`](https://github.com/go-vikunja/vikunja/commit/10ac330459f10892f2fddb2236cc1731a9713543) test: add web tests for OAuth 2.0 authorization flow - [`079729b`](https://github.com/go-vikunja/vikunja/commit/079729bf47478b202f2db7769094b6237bd3572c) chore: lint fixes for OAuth server implementation - [`a806531`](https://github.com/go-vikunja/vikunja/commit/a806531a298d401e9693764f935f3fa66b3d77bf) fix: check disabled account status in authorization code grant - [`38d5505`](https://github.com/go-vikunja/vikunja/commit/38d5505f5ead24f65135863b7bab51b7f3622964) fix: use ServicePublicURL instead of Host header in buildAuthorizeURL ### 📊 Changes **18 files changed** (+1434 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `frontend/src/views/user/Login.vue` (+19 -1) 📝 `frontend/src/views/user/OpenIdAuth.vue` (+18 -1) ➕ `frontend/tests/e2e/user/oauth-authorize.spec.ts` (+135 -0) ➕ `pkg/db/fixtures/oauth_codes.yml` (+2 -0) ➕ `pkg/migration/20260226172819.go` (+51 -0) 📝 `pkg/models/error.go` (+179 -0) 📝 `pkg/models/models.go` (+1 -0) ➕ `pkg/models/oauth_codes.go` (+99 -0) 📝 `pkg/models/setup_tests.go` (+1 -0) 📝 `pkg/modules/auth/auth.go` (+5 -4) ➕ `pkg/modules/auth/oauth2server/authorize.go` (+164 -0) ➕ `pkg/modules/auth/oauth2server/client.go` (+44 -0) ➕ `pkg/modules/auth/oauth2server/client_test.go` (+35 -0) ➕ `pkg/modules/auth/oauth2server/pkce.go` (+34 -0) ➕ `pkg/modules/auth/oauth2server/pkce_test.go` (+51 -0) ➕ `pkg/modules/auth/oauth2server/token.go` (+222 -0) 📝 `pkg/routes/routes.go` (+9 -0) ➕ `pkg/webtests/oauth2_test.go` (+365 -0) </details> ### 📄 Description ## Summary This PR implements an OAuth 2.0 authorization server to enable the Flutter app to authenticate using the authorization code flow with PKCE. ## Changes ### Backend - OAuthCode model (pkg/models/oauth_codes.go) - Stores authorization codes with PKCE challenge, user ID, and expiry - Database migration (pkg/migration/20260226172819.go) - Creates oauth_codes table - OAuth error types (pkg/models/error.go) - Added 7 error types (17001-17007) for OAuth-specific errors - OAuth2 server package (pkg/modules/auth/oauth2server/): - client.go - Client validation (Flutter client ID: vikunja-flutter, redirect URI: vikunja://callback) - pkce.go - PKCE S256 verification - authorize.go - Authorization endpoint handler (GET /api/v1/oauth/authorize) - token.go - Token endpoint handler (POST /api/v1/oauth/token) with authorization_code and refresh_token grant types - Route registration (pkg/routes/routes.go) - Registered OAuth endpoints ### Frontend - Login.vue and OpenIdAuth.vue - Handle OAuth redirect parameter after successful login ### Tests - Unit tests for client validation and PKCE verification - Web tests (pkg/webtests/oauth2_test.go) - 11 integration test cases covering the full OAuth flow ## OAuth Flow 1. Flutter app opens /api/v1/oauth/authorize with client_id, redirect_uri, response_type, code_challenge, code_challenge_method 2. If not logged in, redirects to login page with return URL 3. After login, redirects back to authorize endpoint 4. Authorize endpoint creates code and redirects to vikunja://callback with code 5. Flutter app exchanges code for tokens via POST /api/v1/oauth/token 6. Refresh tokens can be exchanged for new access/refresh token pairs ## Security Features - PKCE (S256) required for all authorization requests - Single-use authorization codes (deleted on use) - 10-minute code expiry - Refresh token rotation - Same-origin validation for OAuth redirects in frontend --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-03-22 15:00:24 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/vikunja#4056