nextcloud / nextcloud/server

[Bug]: OAuth grant page (LoginFlowGrant.vue) broken in Chrome (works in Firefox) — double form submission invalidates state token, regression of #33164

Open Beginner friendly
#62,327 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

0. Needs triage 34-feedback bug feature: authentication feature: vue apps regression
Dominant language
PHP
Stars
36.9k
Forks
5.2k
Avg merge
2d 3h
Merged PRs (30d)
713

Description

⚠️ This issue respects the following points: ⚠️
  • This is a bug, not a question or a configuration/webserver/proxy issue.
  • This issue is not already reported on Github OR Nextcloud Community Forum (searched, no matches for this regression against the current Vue-based grant page).
  • Nextcloud Server is up to date (tested on 34, a currently supported version).
  • I agree to follow Nextcloud's Code of Conduct.
Bug description

Broken in Chrome. Works correctly in Firefox. (These are the two browsers we tested ourselves. The original #33164 additionally reported Chromium, Edge, and Safari as affected — we haven't independently verified those, flagging that distinction since some use a different engine than Chrome.)

When approving an OAuth2 client via the login flow's grant page, the "Grant access" submit button has no disabled/loading state while the form is submitting. In Chrome this allows the form to submit twice from a single page load — confirmed via server logs: the grant page loads exactly once, then two POST /login/flow requests fire two seconds apart with no page reload in between. The first submission succeeds server-side; the second, reusing the same now-invalidated stateToken, fails with 403 "Access forbidden. State tokens do not match." In Firefox, the same steps complete successfully every time.

This looks like a regression of #33164, fixed in 2022 by disabling the button in core/js/login/grant.js. That file no longer exists — the grant page was rewritten as core/src/views/LoginFlowGrant.vue, and the current version (confirmed by reading the source on master as of this writing) has no equivalent protection: no :disabled binding on the <NcButton type="submit">, and the onSubmit handler only intercepts the event when password re-confirmation is required.

Steps to reproduce
  1. In Chrome (fails; the same steps in Firefox succeed — other browsers untested by us), register an OAuth 2.0 client (Admin settings → Security → OAuth 2.0 clients).
  2. Start an authorization_code flow against /apps/oauth2/authorize from that client.
  3. Log in, reach the "Grant access" screen.
  4. Click "Grant access" once.
  5. Observe two POST /login/flow requests in the server log (or browser devtools network tab) from that single click/page load — the second fails with 403 "state tokens do not match," even though only one page load and one intentional click occurred.
Expected behavior

The submit button (or the form) should be protected against re-submission immediately on click, equivalent to what #33166 added to the pre-rewrite page — and should work as reliably in Chrome as it currently does in Firefox.

Nextcloud Server version

34

Additional info

Verified via correlated log inspection (OAuth client application, reverse proxy, and Nextcloud's own nextcloud.log) that Nextcloud's server-side OAuth2/state-token handling is correct on every attempt — the first submission always completes successfully. Confirmed the browser does not reload/navigate between the two submissions (single GET /login/flow/grant followed by two POST /login/flow, no intervening page load). We tested Chrome (reproduces) and Firefox (does not reproduce) ourselves; the original #33164 also lists Chromium, Edge, and Safari as affected, which we have not independently confirmed.

Current file: https://github.com/nextcloud/server/blob/master/core/src/views/LoginFlowGrant.vue

This is pure client-side JS behavior, independent of OS/PHP/webserver/database, so those fields are omitted.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with core/src/views/LoginFlowGrant.vue, especially the NcButton submit element and onSubmit handler, and compare them with the issue's description of the former core/js/login/grant.js behavior. Reproduce the grant flow in Chrome while watching the network log. Done means one click produces one POST /login/flow and the grant completes without a state-token 403.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.