-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Google Authentication #2790
Comments
This code is partial (and unfortunately non-elegant) solution. It:
A key aspect that is missed here, is that in the case that the user goes straight ahead to the gradio endpoint, there is no redirection to login and the user is stuck there. Is there a way by any chance to redirect from within the gradio demo back to import json
from authlib.integrations.base_client import OAuthError
from fastapi import FastAPI
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import HTMLResponse, RedirectResponse
from starlette.requests import Request
import gradio as gr
from authlib.integrations.starlette_client import OAuth
from starlette.config import Config
# CODE FOR NEW APP
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="!secret")
config = Config('.env')
oauth = OAuth(config)
CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration'
oauth.register(
name='google',
server_metadata_url=CONF_URL,
client_kwargs={
'scope': 'openid email profile'
}
)
@app.get('/')
async def homepage(request: Request):
user = request.session.get('user')
if user:
data = json.dumps(user)
html = (
f'<pre>{data}</pre>'
'<a href="/logout">logout</a>'
'<br>'
'<a href="/gradio">demo</a>'
)
return HTMLResponse(html)
return HTMLResponse('<a href="/login">login</a>')
@app.get('/login')
async def login(request: Request):
redirect_uri = request.url_for('auth')
return await oauth.google.authorize_redirect(request, redirect_uri)
@app.get('/auth')
async def auth(request: Request):
print(f"before request user {request.session.get('user')}")
try:
token = await oauth.google.authorize_access_token(request)
except OAuthError as error:
return HTMLResponse(f'<h1>{error.error}</h1>')
user = token.get('userinfo')
if user:
request.session['user'] = dict(user)
print(f"after request user {request.session.get('user')}")
return RedirectResponse(url='/')
@app.get('/logout')
async def logout(request: Request):
request.session.pop('user', None)
return RedirectResponse(url='/')
# CODE FOR MOUNTED GRADIO APP
def update(name, request: gr.Request):
return f"Welcome to Gradio, {name}!\n{request.request.session.get('user')}"
def make_demo_visible(request: gr.Request):
if request.request.session.get('user'):
return gr.update(visible=True), gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(value="Looks like you are not logged in. Please login at the main app.")
with gr.Blocks() as demo:
start_btn = gr.Button("Press Here to initialize the demo!")
with gr.Row():
inp = gr.Textbox(placeholder="What is your name?", visible=False)
out = gr.Textbox(visible=False)
btn = gr.Button("Run", visible=False)
start_btn.click(make_demo_visible, outputs=[inp, out, btn, start_btn])
btn.click(fn=update, inputs=inp, outputs=out)
gradio_app = gr.mount_gradio_app(app, demo, "/gradio") |
Google Firebase offers an excellent solution to this use case. I have a useful API on the backend server data processing that handles inbound authorization requests from a Google Firebase front-end. (I would be happy to offer my code to anyone who asks.) Google Firebase front-end support is excellent. I have a React UI from previous repositories and directing users to that landing page; require them to log in with the Firebase token or via Google Login, then redirects the user to the primary front-end of the app (the Gradio UI in this case). I have not installed that into my current Gradio UI only because I am only now developing the app via Gradio, though the software has served me excellently for several years now. It would even be relatively easy to embed an |
Hi @davidbernat, inroder to request permissions from google oauth. my app needs to redirect to a url provided by google api. The problem is that gradio doesn't offer a redirect feature. |
Hey @yuvalkirstain , Can you give me a way to redirect the user to a given url, I'll be really happy if you can help me. |
Hey @davidbernat , I'm trying to implement exactly this, add authentication to a gradio app, pass in a UUID and make blocks visible after comparing the UUID with what's in a database. If you'd be willing to share any code or give any advice, that would be really helpful! |
Has anyone made any progress on this? I would like to also have firebase authenticate users and redirect to my app once authenticated |
@jerpint I found that gradio is built on top of fastapi, so for me I mounted gradio app on top of a fastapi app that handle authentication. |
@zinoubm i was thinking of doing something similar, do you have a working example? |
@jerpint Sorry about that, It was for a client so I can't share it. But I believe the docs have some useful resources. |
@jerpint , You may find this helpful https://gradio.app/sharing-your-app/#mounting-within-another-fastapi-app |
I solved this problem. Please mark this issue as complete. Starlight LLC. Thanks. |
Solved? Where can I see this enhancement @davidbernat? I just came across a case where I will need to integrate Google login to a Gradio app and stumbled upon this discussion just now. |
Unfortunately until Google and Apple shift toward more open models of research and data in their AI division we have decided to close our doors to each company here at Starlight LLC and Starlight.AI LLC. You may feel free to reach out to me directly, though I wish to not discuss this project at this time as Google has shifted its backend priorities anyway, and legal action is already in discussion. |
So there's no other way than to wrap it in a FastAPI app and then implement auth for that FastAPI app? |
@davidbernat you've not solved anything as far as I can see. Please keep this issue open until the functionality is implemented in Gradio, or there is a simple process we can follow to make it work well. |
@yuvalkirstain Have you hosted this somewhere so it'll be helpful for us to take a look? |
@zinoubm I know you can't share your code, but could you explain how you access the gr.Request to get the user information? I tried the above solution by @yuvalkirstain but it only works when the queue is disabled. Enabling the queue makes request.request be None and the solution no longer works. |
Any final update on this thread? |
What if we use some Middleware from FastAPI? |
The issue is not the API. All that is required is an HTML element that can create API calls via JS or, better yet, a hook into a Python function. Unfortunately, my understanding is that Gradio is not providing those yet, and I created my own. |
@yuvalkirstain @jerpint @kambleakash0 @dhruv-anand-aintech
In the middleware you'll find these lines of code:
I included this because I found that when using this middleware, the fastapi makes POST request to Please provide feedback on this solution and let me know if there's a better solution than this |
Thanks @EshamAaqib yes that works. I do something similar here: https://huggingface.co/spaces/gradio/oauth-example/blob/6c746b5828864cb057ed5d9a9fe725d91d6723fa/app.py#L53 gr.route_utils.get_root_url gets the root url and adds https if running on https (but I guess better to be explicit about this since get_root_url is an internal functions and could change) |
@abidlabs Does the code in gradio have this fixed so handles generally? Or have to tweak this wrapper code every time for either http or https cases? |
@abidlabs For this google auth solution, seems to be better to avoid having to mount things and be just a part of gradio. Not like google is a random thing, everyone uses it for auth. So better to be in gradio as option not as external mount. That way no issues with rest of usage, like options in .launch |
Not really possible, because you need to define other routes to handle the login page, auth page, etc. I considered other options, but its better to provide a template and then let users define these routes so that they can modify them as needed rather than hide them behind a layer of abstraction. |
What about all the launch parameters? Can can one pass all of those through to gradio? |
Depends which ones. If there's something else you need, let us know and we can add support |
These are the ones we set that I don't know how to pass through:
|
|
Also out of curiosity, why do you need |
In general for testing, I launch server then the test in single process, so I don't want gradio to block. |
FYI, I'd also pass |
I'd guess if uvicorn doesn't support |
It doesn't really make sense to pass in Everything else, I have added here, if you want to give it a spin: #7734 |
Any thoughts on "workers"? fastapi/fastapi#1495 (comment) I hit:
It seems like it may just be a naming issue, but I'm not expert. |
@abidlabs Next question, how do to demo.load() with this mounting way? i.e. I have demo.load() run some login stuff to setup user for given user that logged in via normal auth using gr.Request. But with the google auth way, demo.load() and demo.queue() are never done AFAIK. Which gets to the next question, which is what about demo.queue? API access with auth was done recently in gradio 4, but how about through google auth? What about concurrency limit controls? |
Hi @pseudotensor you can still do |
Hi @abidlabs , hmm, it's not doing what's in demo.load(), however. I'll double check. and make repro if there is issue. Thanks! |
@abidlabs Ok, demo.load() issue was just user mistake. Last thing I'm wondering is how to identify a user. gr. requests has username but nothing else that seems unique, and that username is just the user's google full name, but that can be same for different people. Is there way to get the email that was used? |
@abidlabs I looked into the starlette request object in your code, but nothing has email or any other things except cookie (which doesn't match in persistent way). Seems required to get email not just user from google to ensure authentication is proper. In non-google case, we have user + password to disentangle and verify, but here name is not enough. |
@abidlabs Ok, I figured out. The requests session also has email, picture, etc. So I make user name name + email + picture url and then process that in main gradio app as required. name+email is for auth, pic just for showing user. |
Yes exactly, you can pass whatever attributes you want as a dict in |
Ya that would be useful to know. At moment I did some ugly string appending and splitting to handle. |
@abidlabs QQ Can the login demo part (before actual demo) show both the normal auth login in addition to the google button to login via google? I'd like to be able to support either option instead of only one. I'm not quite sure how to do that. Thanks! |
Hi @pseudotensor no we don't support both the regular auth and auth_dependency and don't really have plans to add this as it could lead to a confusing security model. That being said, |
@abidlabs - sorry for the beginner questions... I've got the google auth working as shown in your demo code, etc.. (thanks!) But in the category of "no good deed goes unpunished" -- Do you have any idea what it would take to integrate Firebase / Identity Platform authentication? All of their samples show some form of HTML being integrated into an application - is that something I could achieve with Custom components? https://www.gradio.app/custom-components/gallery Or do you think the existing Google auth support would work with some python tweaking? Firebase Authentication |
Can you share an example of this? If you need to add custom HTML or JS to your Gradio application, you don't necessarily need to build a custom component, you might be able to do this with https://www.gradio.app/guides/custom-CSS-and-JS |
Sorry for the slow reply... https://cloud.google.com/identity-platform/docs/sign-in-user-email#sign_in_the_user Shows this basic flow: import { initializeApp } from 'firebase/app';
const firebaseConfig = {
apiKey: "API_KEY",
authDomain: "AUTH_DOMAIN"
};
const app = initializeApp(firebaseConfig); and further down, a more complete solution... notice calls to login function: import { initializeApp } from 'firebase/app';
import {
onAuthStateChanged,
signInWithEmailAndPassword,
getAuth
} from 'firebase/auth';
const firebaseConfig = {
apiKey: "API_KEY",
authDomain: "AUTH_DOMAIN"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app, {/* extra options */ });
document.addEventListener("DOMContentLoaded", () => {
onAuthStateChanged(auth, (user) => {
if (user) {
document.getElementById("message").innerHTML = "Welcome, " + user.email;
}
else {
document.getElementById("message").innerHTML = "No user signed in.";
}
});
signIn();
});
function signIn() {
const email = "EMAIL_ID";
const password = "PASSWORD";
signInWithEmailAndPassword(auth, email, password)
.catch((error) => {
document.getElementById("message").innerHTML = error.message;
});
} Thanks for the pointer here - I'll have a look - https://www.gradio.app/guides/custom-CSS-and-JS |
In some apps, we want to filter harmful users or bots. I think that having a component that enables google authentication (rather than a username, passowrd authentication) in gradio can be very helpful.
Describe the solution you'd like
I'd like to have an authentication component that receives the details of the user so it can decide if the user may access the app or not.
The text was updated successfully, but these errors were encountered: