    async def get(self):
        """GET /oauth/authorization

        Render oauth confirmation page:
        "Server at ... would like permission to ...".

        Users accessing their own server or a blessed service
        will skip confirmation.
        """

        uri, http_method, body, headers = self.extract_oauth_params()
        try:
            with mock.patch.object(
                self.oauth_provider.request_validator,
                "_current_user",
                self.current_user,
                create=True,
            ):
                (
                    requested_scopes,
                    credentials,
                ) = self.oauth_provider.validate_authorization_request(
                    uri, http_method, body, headers
                )
            credentials = self.add_credentials(credentials)
            client = self.oauth_provider.fetch_by_client_id(credentials['client_id'])
            allowed = False

            # check for access to target resource
            if client.spawner:
                scope_filter = self.get_scope_filter("access:servers")
                allowed = scope_filter(client.spawner, kind='server')
            elif client.service:
                scope_filter = self.get_scope_filter("access:services")
                allowed = scope_filter(client.service, kind='service')
            else:
                # client is not associated with a service or spawner.
                # This shouldn't happen, but it might if this is a stale or forged request
                # from a service or spawner that's since been deleted
                self.log.error(
                    f"OAuth client {client} has no service or spawner, cannot resolve scopes."
                )
                raise web.HTTPError(500, "OAuth configuration error")

            if not allowed:
                self.log.error(
                    f"User {self.current_user} not allowed to access {client.description}"
                )
                raise web.HTTPError(
                    403, f"You do not have permission to access {client.description}"
                )

            # subset 'raw scopes' to those held by authenticating user
            requested_scopes = set(requested_scopes)
            user = self.current_user
            # raw, _not_ expanded scopes
            user_scopes = roles.roles_to_scopes(roles.get_roles_for(user.orm_user))
            # these are some scopes the user may not have
            # in 'raw' form, but definitely have at this point
            # make sure they are here, because we are computing the
            # 'raw' scope intersection,
            # rather than the expanded_scope intersection

            required_scopes = {*scopes.identify_scopes(), *scopes.access_scopes(client)}
            user_scopes |= {"inherit", *required_scopes}

            allowed_scopes, disallowed_scopes = scopes._resolve_requested_scopes(
                requested_scopes,
                user_scopes,
                user=user.orm_user,
                client=client,
                db=self.db,
            )

            if disallowed_scopes:
                self.log.warning(
                    f"Service {client.description} requested scopes {','.join(requested_scopes)}"
                    f" for user {self.current_user.name},"
                    f" granting only {','.join(allowed_scopes) or '[]'}."
                )

            if not self.needs_oauth_confirm(self.current_user, client, allowed_scopes):
                self.log.debug(
                    "Skipping oauth confirmation for %s accessing %s",
                    self.current_user,
                    client.description,
                )
                # this is the pre-1.0 behavior for all oauth
                self._complete_login(uri, headers, allowed_scopes, credentials)
                return

            # discard 'required' scopes from description
            # no need to describe the ability to access itself
            scopes_to_describe = allowed_scopes.difference(required_scopes)

            if not scopes_to_describe:
                # TODO: describe all scopes?
                # Not right now, because the no-scope default 'identify' text
                # is clearer than what we produce for those scopes individually
                scope_descriptions = [
                    {
                        "scope": None,
                        "description": scopes.scope_definitions['(no_scope)'][
                            'description'
                        ],
                        "filter": "",
                    }
                ]
            elif 'inherit' in scopes_to_describe:
                allowed_scopes = scopes_to_describe = ['inherit']
                scope_descriptions = [
                    {
                        "scope": "inherit",
                        "description": scopes.scope_definitions['inherit'][
                            'description'
                        ],
                        "filter": "",
                    }
                ]
            else:
                scope_descriptions = scopes.describe_raw_scopes(
                    scopes_to_describe,
                    username=self.current_user.name,
                )
            # Render oauth 'Authorize application...' page
            auth_state = await self.current_user.get_auth_state()
            self.write(
                await self.render_template(
                    "oauth.html",
                    auth_state=auth_state,
                    allowed_scopes=allowed_scopes,
                    scope_descriptions=scope_descriptions,
                    oauth_client=client,
                )
            )

        # Errors that should be shown to the user on the provider website
        except oauth2.FatalClientError as e:
            raise web.HTTPError(e.status_code, e.description)

        # Errors embedded in the redirect URI back to the client
        except oauth2.OAuth2Error as e:
            self.log.error("OAuth error: %s", e.description)
            self.redirect(e.in_uri(e.redirect_uri))
GET /oauth/authorization

Render oauth confirmation page:
"Server at ... would like permission to ...".

Users accessing their own server or a blessed service
will skip confirmation.
jupyterhub/apihandlers/auth.py