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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions