"""Predefined button to sign in with Hugging Face in a Gradio Space.""" from __future__ import annotations import json from collections.abc import Sequence from pathlib import Path from typing import TYPE_CHECKING, Literal from gradio_client.documentation import document from gradio import oauth, utils from gradio.components import Button, Component from gradio.context import get_blocks_context from gradio.routes import Request if TYPE_CHECKING: from gradio.components import Timer from gradio.events import Dependency @document() class LoginButton(Button): """ Creates a "Sign In" button that redirects the user to sign in with Hugging Face OAuth. Once the user is signed in, the button will act as a logout button, and you can retrieve a signed-in user's profile by adding a parameter of type `gr.OAuthProfile` to any Gradio function. This will only work if this Gradio app is running in a Hugging Face Space. Permissions for the OAuth app can be configured in the Spaces README file, as described here: https://huggingface.co/docs/hub/en/spaces-oauth. For local development, instead of OAuth, the local Hugging Face account that is logged in (via `hf auth login`) will be available through the `gr.OAuthProfile` object. Demos: login_with_huggingface Guides: sharing-your-app """ is_template = True def __init__( self, value: str = "Sign in with Hugging Face", logout_value: str = "Logout ({})", *, every: Timer | float | None = None, inputs: Component | Sequence[Component] | set[Component] | None = None, variant: Literal["primary", "secondary", "stop", "huggingface"] = "huggingface", size: Literal["sm", "md", "lg"] = "lg", icon: str | Path | None = utils.get_icon_path("huggingface-logo.svg"), link: str | None = None, link_target: Literal["_self", "_blank", "_parent", "_top"] = "_self", visible: bool | Literal["hidden"] = True, interactive: bool = True, elem_id: str | None = None, elem_classes: list[str] | str | None = None, render: bool = True, key: int | str | tuple[int | str, ...] | None = None, preserved_by_key: list[str] | str | None = "value", scale: int | None = None, min_width: int | None = None, ): """ Parameters: logout_value: The text to display when the user is signed in. The string should contain a placeholder for the username with a call-to-action to logout, e.g. "Logout ({})". """ self.logout_value = logout_value super().__init__( value, every=every, inputs=inputs, variant=variant, size=size, icon=icon, link=link, link_target=link_target, visible=visible, interactive=interactive, elem_id=elem_id, elem_classes=elem_classes, render=render, key=key, preserved_by_key=preserved_by_key, scale=scale, min_width=min_width, ) if get_blocks_context(): self.activate() def activate(self): # Taken from https://cmgdo.com/external-link-in-gradio-button/ # Taking `self` as input to check if user is logged in # ('self' value will be either "Sign in with Hugging Face" or "Signed in as ...") _js = _js_handle_redirect.replace( "BUTTON_DEFAULT_VALUE", json.dumps(self.value) ).replace("REDIRECT_URL", self.page) self.click(fn=None, inputs=[self], outputs=None, js=_js) self.attach_load_event(self._check_login_status, None) def _check_login_status(self, request: Request) -> LoginButton: # Each time the page is refreshed or loaded, check if the user is logged in and adapt label session = getattr(request, "session", None) or getattr( request.request, "session", None ) if session is None: # Cookie set but user not logged in return LoginButton(self.value, interactive=True) oauth_info = oauth._get_valid_oauth_info_from_session(session) if oauth_info is None: # Cookie set but user not logged in return LoginButton(self.value, interactive=True) # User is correctly logged in username = oauth_info["userinfo"]["preferred_username"] return LoginButton(self.logout_value.format(username), interactive=True) from typing import Callable, Literal, Sequence, Any, TYPE_CHECKING from gradio.blocks import Block if TYPE_CHECKING: from gradio.components import Timer from gradio.components.base import Component # JS code to redirects to /login/huggingface if user is not logged in. # If user is logged in, redirect to /logout page. Always happens # on the same tab. _js_handle_redirect = """ (buttonValue) => { uri = buttonValue === BUTTON_DEFAULT_VALUE ? '/login/huggingface?_target_url=/REDIRECT_URL' : '/logout?_target_url=/REDIRECT_URL'; window.parent?.postMessage({ type: "SET_SCROLLING", enabled: true }, "*"); setTimeout(() => { window.location.assign(uri + window.location.search); }, 500); } """