Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/youtube.py (Python)

Code before:
            if isinstance(e.cause, HTTPError):
                error = self._read_oauth_error_response(e.cause.response)
                if error == 'invalid_grant':
                    # RFC6749 § 5.2
                    raise ExtractorError(
                        'Failed to refresh access token: Refresh token is invalid, revoked, or expired (invalid_grant)',
                        expected=True, video_id=self._OAUTH_DISPLAY_ID)
                raise ExtractorError(
                    f'Failed to refresh access token: Authorization server returned error {error}', video_id=self._OAUTH_DISPLAY_ID)
            raise
        return token_response

    @property
    def _oauth_authorize(self):
        code_response = self._download_json(
            self._OAUTH_DEVICE_AUTHORIZATION_ENDPOINT,
            video_id=self._OAUTH_DISPLAY_ID,
            note='Initializing authorization flow',
            data=json.dumps({
                'client_id': self._OAUTH_CLIENT_ID,
                'scope': self._OAUTH_SCOPE,
            }).encode(),
            headers={'Content-Type': 'application/json'})

        verification_url = traverse_obj(code_response, 'verification_url', {str})
        user_code = traverse_obj(code_response, 'user_code', {str})
        if not verification_url or not user_code:
            raise ExtractorError(
                'Authorization server did not provide verification_url or user_code', video_id=self._OAUTH_DISPLAY_ID)

        # note: The whitespace is intentional
        self.to_screen(f'{self._OAUTH_DISPLAY_ID}: To give yt-dlp access to your account, go to  {verification_url}  and enter code  {user_code}')

        # RFC8628 § 3.5: default poll interval is 5 seconds if not provided
        poll_interval = traverse_obj(code_response, 'interval', {int}, default=5)

        for retry in self.RetryManager():
            while True:
                try:
                    token_response = self._download_json(
                        self._OAUTH_TOKEN_ENDPOINT,
                        video_id=self._OAUTH_DISPLAY_ID,
                        note=False,
                        errnote='Failed to request access token',
                        data=json.dumps({
                            'client_id': self._OAUTH_CLIENT_ID,
                            'client_secret': self._OAUTH_CLIENT_SECRET,
                            'device_code': code_response['device_code'],
                            'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
                        }).encode(),
                        headers={'Content-Type': 'application/json'})

Review comment (suggestion):
```suggestion
        verification_url = traverse_obj(code_response, ('verification_url', {str}))
        user_code = traverse_obj(code_response, ('user_code', {str}))
```

Code after:
            if isinstance(e.cause, HTTPError):
                error = self._read_oauth_error_response(e.cause.response)
                if error == 'invalid_grant':
                    # RFC6749 § 5.2
                    raise ExtractorError(
                        'Failed to refresh access token: Refresh token is invalid, revoked, or expired (invalid_grant)',
                        expected=True, video_id=self._OAUTH_DISPLAY_ID)
                raise ExtractorError(
                    f'Failed to refresh access token: Authorization server returned error {error}',
                    video_id=self._OAUTH_DISPLAY_ID)
            raise
        return token_response

    @property
    def _oauth_authorize(self):
        code_response = self._download_json(
            self._OAUTH_DEVICE_AUTHORIZATION_ENDPOINT,
            video_id=self._OAUTH_DISPLAY_ID,
            note='Initializing authorization flow',
            data=json.dumps({
                'client_id': self._OAUTH_CLIENT_ID,
                'scope': self._OAUTH_SCOPE,
            }).encode(),
            headers={'Content-Type': 'application/json'})

        verification_url = traverse_obj(code_response, ('verification_url', {str}))
        user_code = traverse_obj(code_response, ('user_code', {str}))
        if not verification_url or not user_code:
            raise ExtractorError(
                'Authorization server did not provide verification_url or user_code', video_id=self._OAUTH_DISPLAY_ID)

        # note: The whitespace is intentional
        self.to_screen(
            f'{self._OAUTH_DISPLAY_ID}: To give yt-dlp access to your account, '
            f'go to  {verification_url}  and enter code  {user_code}')

        # RFC8628 § 3.5: default poll interval is 5 seconds if not provided
        poll_interval = traverse_obj(code_response, ('interval', {int}), default=5)

        for retry in self.RetryManager():
            while True:
                try:
                    token_response = self._download_json(
                        self._OAUTH_TOKEN_ENDPOINT,
                        video_id=self._OAUTH_DISPLAY_ID,
                        note=False,
                        errnote='Failed to request access token',
                        data=json.dumps({
                            'client_id': self._OAUTH_CLIENT_ID,
                            'client_secret': self._OAUTH_CLIENT_SECRET,
                            'device_code': code_response['device_code'],