Skip to content

Token Generated From Partial Consent Results in Stuck 403 State #115

Description

In my manual testing of the React Drive Picker, it's generally been working great! However, there is a particular error state that seems relatively easy for a user to reach by mistake and it's not very clear what the user can/should do to recover.

Basically, when I open the first oauth popup, I can select the Google account I want to provide consent/perms to my application for. I'm then prompted to grant access to my account's email address and then, separately, access to my Drive. If I forget to check the box next to the Drive permission and click Continue, a "valid" token is generated, however it has missing scopes so it will cause the Drive Picker iframe itself to open in an unrecoverable 403 state.

As a user, I can press the esc key to close out the iframe, reinitiate the entire sequence, and only need to provide Drive access which makes the UX cleaner/simpler and less error-prone on the second pass.

I believe this is roughly the flow that causes the break/missed cleanup (isPickerVisible):

  1. User clicks "Upload from Google Drive" → isPickerVisible is set to true → the web component mounts into the DOM.
    a. isPickerVisible is a state variable we introduced in our app which controls whether the DrivePicker is mounted or unmounted. I believe setting it to false (and therefore unmounting the DrivePicker) causes the disconnectedCallback to fire which calls dispose().
  2. When the component mounts, connectedCallback() fires, which calls scheduleBuild() → build().
  3. build() calls this.requestAccessToken() at line 252 of drive-picker-element.ts
  4. requestAccessToken() (in utils.ts) calls google.accounts.oauth2.initTokenClient({...}).requestAccessToken() — this opens the Google OAuth consent popup/iframe.
  5. The user sees the granular consent screen (because you're requesting userinfo.email + drive.file — two non-Sign-In scopes). Google's granular consent shows checkboxes. The user unchecks one of the scopes (e.g. drive.file), then clicks "Continue."
  6. GIS still calls the callback (not error_callback) with a TokenResponse that has a valid access_token — but the scope field only includes the scopes the user actually granted. This is documented Google behavior.
  7. The requestAccessToken in utils.ts (lines 40-58) resolves the promise with the full response (no scope validation)
  8. Back in build(), the requestAccessToken() promise resolves. The then() handler in DrivePickerElement.requestAccessToken() checks for access_token, but only its existence.
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions