Super basic authentication

I implemented very rudimentary simple HTTP authentication for Prodigy and wanted to share it with anyone who’s interested. I know this isn’t secure but it’s the best I could do with my minimal web skills. It would be great to have something like Jupyter’s token-based authentication some day.

At line 43 of app.py, add this:

authentication = hug.authentication.basic(hug.authentication.verify('annotator1', 'mypassword'))

@hug.static('/', requires = authentication)
def serve_static():
    # NB! This currently serves whole drive! Does nothing to prevent '../'
    return (str(Path(__file__).parent / 'static'),)

I used example code from the hug repo.

1 Like

Thanks! Glad to hear this was easy.

Nice! Would be really useful if integrated inside Prodigy.

2 Likes

Sorry I feel like I am missing something. How would you apply this to the specific prodigy web app instance? Or are you suggesting modifying the Prodigy source code?

Yes, Prodigy ships with the source for its app.py, so you can easily adapt it or see how it works and write a similar wrapper using Hug or a different library.

Since this thread was started, @andy has actually developed a super cool open-source extension for Prodigy that implements a multi-user setup plus various other features. You can find it here:

Aw that makes sense now. Thanks for the quick response! I’m going to give this a try :+1:

I applied @andy’s cool hug authentication but it doesn’t work.
I get this Oops, something went wrong :( error after entering the credentials.
I noticed on Chrome’s developer tools is that the call to /project fails with HTTP 401 with the following error message: {"errors":{"Invalid Authentication":"Provided api_jwt credentials were invalid"}}

Have I missed something?
Thanks

1 Like

@koAlech Hurray for authenticating users, and welcome!

We’ve begun integrating more full-featured authentication for Prodigy Scale, and the snippet you used conflicts with that code.

A workaround is to remove the occurrences of the string , requires=conditional_api_token from app.py.

This will remove your ability to use the PRODIGY_JWT_* environment variables, but if you want to use basic auth, that should be no problem.

edit: there’s a better fix below

@justindujardin Thanks for the warm welcome!
I’m kind of a newbie with prodigy but so far it’s just awesome!

Thanks for the workaround but that just authenticates /.
It makes the APIs accessible by anyone.

I guess my only option right now is going with ngrok …
Any other ideas?

1 Like

Hah, you're right, and I found a fix!

In app.py around line 43 there is an if statement that checks for the existence of an "Authorization" header value:

@authenticator
def api_jwt(request, response, verify_user, **kwargs):
    token = request.get_header("Authorization")
    bearer_prefix = "Bearer "
    if token:
    ...

Updating it to ensure that Authorization header is for a bearer token (and not basic auth) fixes the conflict without removing JWT support:

@authenticator
def api_jwt(request, response, verify_user, **kwargs):
    token = request.get_header("Authorization")
    bearer_prefix = "Bearer "
    if token and bearer_prefix in token:
    ...
1 Like

I was having authentication issues using ngrok, I suppose the basic authentication header used by ngrok conflicts with the JWT validation, I apply your suggested change and it works fine, thanks.

1 Like

I ended up creating a https proxy with basic authentication using nginx. Works great after this change!
The option of enabling basic authentication using hug is not a valid option for us as it only protects / and leaves the API calls publicly accessible.
Thanks for the help @justindujardin!