Add web tests covering the authorize endpoint, token exchange, PKCE
verification, single-use codes, and refresh token rotation. Add unit
tests for redirect URI validation and PKCE. Add E2E test for the full
browser-based authorization code flow with login redirect.
Extract setupApiUrl helper for E2E tests to avoid duplication.
Add /oauth/authorize frontend route with OAuthAuthorize.vue that
handles the OAuth authorization flow: validates required query params,
calls the API to generate an authorization code, and redirects to the
callback URI. Authentication is handled by the standard router guard.
Add POST /api/v1/oauth/token supporting authorization_code and
refresh_token grant types. Validates PKCE, exchanges codes for
JWT access tokens with refresh token rotation. Uses the shared
RefreshSession helper for the refresh grant.
Add POST /api/v1/oauth/authorize behind auth middleware. Validates
OAuth parameters (response_type, redirect_uri, PKCE), fetches the
authenticated user, creates an authorization code, and returns it
as JSON for the frontend to handle the redirect.
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.
Add the OAuthCode model for storing short-lived authorization codes
with PKCE challenges. Codes are hashed (SHA-256) before storage and
are single-use with a 10-minute expiry. Add the database migration
and OAuth-specific error types.
The cookie-based /user/token/refresh handler had session refresh logic
(lookup, expiry check, token rotation, user fetch, JWT generation)
that will be reused by the OAuth token endpoint. Extract it into
auth.RefreshSession() and rewrite RefreshToken to use it.
TickTick CSV exports don't guarantee parent tasks appear before their
subtasks. When a child row came first, the shared migration pipeline
tried to create a title-less placeholder for the missing parent, which
failed with 'Task title cannot be empty'.
Resolvesgo-vikunja/vikunja#2487
Updates picomatch to 2.3.2 and 4.0.4 in the frontend workspace to
address CVE for ReDoS via extglob quantifiers and method injection
in POSIX character classes.
Triggers on release publish or manual dispatch. Uses the nixpkgs
update infrastructure (maintainers/scripts/update.nix) to update
both vikunja and vikunja-desktop, then pushes to the go-vikunja
nixpkgs fork and opens a PR on NixOS/nixpkgs.
Skips early if an open update PR already exists.
Rename the frontend parsing module from `parseTaskText` to `quickAddMagic`
for clarity. The module handles much more than text parsing — it's the
core of the quick add magic feature. This rename makes its purpose
immediately obvious and aligns with how the feature is referenced
throughout the UI and documentation.
No logic changes — only directory/file renames and import updates.
When a PR is merged via merge queue, the issue close event has no
commit_id and no referenced event. Fall back to the GraphQL
closedByPullRequestsReferences field to find the closing PR.
Also simplifies the commit-to-PR lookup by using
listPullRequestsAssociatedWithCommit instead of iterating all PRs.
Adjust test assertions to reflect that projects inheriting archived
state from parents are now correctly filtered out of ReadAll results,
task collections, and search results across all database backends.
Replace the Go-side propagateArchivedState function with in-CTE
propagation. The recursive SELECT uses (ap.is_archived OR p.is_archived)
to inherit archived state from parent projects. The outer query uses
GROUP BY with MAX(CAST(is_archived AS int)) to handle projects
accessible via both direct permissions and parent traversal. When
getArchived=false, a HAVING clause filters out archived projects.
The is_archived filter is removed from getUserProjectsStatement so
archived parents enter the CTE and propagation works correctly.
Replace the one-liner redirect with a self-contained guide covering
development setup, testing, submitting changes, code style, translations,
and architecture overview.
Use engine.TableInfo(bean) instead of manually checking the TableName
interface and falling back to the mapper. This delegates all table name
resolution to xorm's own logic.
RegisteredTableNames() was using the xorm name mapper to derive table
names from Go struct type names, ignoring custom TableName() methods.
This caused `vikunja dump` to look for `database_notification` instead
of the actual table `notifications`, resulting in a fatal error.
Fixesgo-vikunja/vikunja#2464
Move the watchEffect call after the validate function declaration
to fix "Cannot access 'c' before initialization" error that occurred
when visiting the password update page with validateInitially=true.
Fixes#2463
Teams synced from OpenID Connect providers were always named with "(OIDC)"
suffix (e.g., "DevTeam (OIDC)"). This changes it to use the configured
provider name instead (e.g., "DevTeam (Keycloak)"), making it easier to
identify which provider a team came from when multiple OIDC providers are
configured. Existing team names will be updated automatically on next user
login.
https://claude.ai/code/session_012LXXPvYe6i27WTcha1PL7A