Authentication guide for Panel app on Heroku?

I was looking for a step by step guide on how to add a simple authentication to apps deployed on Heroku but couldn’t find any.

Can someone point me in the right direction?

I’ve seen the authentication page on Panel website but that doesn’t really go into detail.

1 Like

Hi @danmaty

Welcome to the community.

What would you like to authenticate to? Simple Username and Password? AWS, Azure, Google, Github, Facebook or?

1 Like

Hi @Marc,

I’d like to add something simple to a Heroku based Panel app. I was trying to add Google, Github and Okta just to see if OAuth would suit my needs but all I ended up with was a blank page with Error 500.

As I couldn’t find a foolproof guide I’m not sure if something was wrong with the OAuth provider setup or if it’s Heroku related.

I was hoping to have something similar to the one-liner solution of Dash or what Anvil has to offer.

All suggestions are appreciated.

It would be great of if authentication support is also for Microsoft active directory services for internal networks users inside the company networks

1 Like

I hope within this year to get experience configuring Azure AD with Panel.

1 Like

@danmaty Could you break down what exactly you’ve tried? Also set the PANEL_LOG_LEVEL to DEBUG and then paste what you see in the logs when trying to authenticate.

Hi @philippjfr,

In a nutshell…

  • The app itself on Heroku just pulls some data from an external source and displays it with “material.servable()”

  • I’ve added the below to the Procfile that being pushed to Heroku:
    –oauth-provider=github --oauth-key=***** --oauth-secret=***** --cookie-secret=secret --log-level=debug

  • On GitHub for both the Homepage URL and the Authorization callback URL I’ve put in http://*****.herokuapp.com

  • I’ve tried to access my app once the above was done and GitHub actually asked me to authorise myself if that makes sense.

  • Then all I get is a “500: Internal Server Error” text on my app page.

And the below is from the log.

2020-11-25T12:36:48.382180+00:00 heroku[router]: at=info method=GET path=“/” host=.herokuapp.com request_id=c4aa1147-3dd9-4296-b13a-76b824c2c19c fwd=“176.255.67.188” dyno=web.1 connect=1ms service=2ms status=302 bytes=191 protocol=http
2020-11-25T12:36:48.483422+00:00 heroku[router]: at=info method=GET path=“/login?next=%2F” host=
.herokuapp.com request_id=b2020086-2dca-45d0-9cc2-32285a2a4418 fwd=“...” dyno=web.1 connect=1ms service=3ms status=302 bytes=597 protocol=http
2020-11-25T12:36:48.480873+00:00 app[web.1]: 2020-11-25 12:36:48,480 GithubLoginHandler received login request
2020-11-25T12:36:48.481656+00:00 app[web.1]: 2020-11-25 12:36:48,481 GithubLoginHandler making authorize request
2020-11-25T12:36:54.364297+00:00 heroku[router]: at=info method=GET path=“/?code=4bce10c0d0b19ffa8b31&state=30d69d0bf32344f996c56a4cf54cba95” host=.herokuapp.com request_id=d9743819-3b1a-49aa-b1e4-31e1ee3e0a7f fwd=“...” dyno=web.1 connect=1ms service=2ms status=302 bytes=264 protocol=http
2020-11-25T12:36:54.643449+00:00 heroku[router]: at=info method=GET path=“/login?next=%2F%3Fcode%3D4bce10c0d0b19ffa8b31%26state%3D30d69d0bf32344f996c56a4cf54cba95” host=
.herokuapp.com request_id=d9e48151-a65b-475e-95ea-1fa7fbd0d308 fwd=“...” dyno=web.1 connect=0ms service=186ms status=500 bytes=355 protocol=http
2020-11-25T12:36:54.458891+00:00 app[web.1]: 2020-11-25 12:36:54,458 GithubLoginHandler received login request
2020-11-25T12:36:54.459876+00:00 app[web.1]: 2020-11-25 12:36:54,459 GithubLoginHandler making access token request.
2020-11-25T12:36:54.641404+00:00 app[web.1]: 2020-11-25 12:36:54,640 Uncaught exception GET /login?next=%2F%3Fcode%3D4bce10c0d0b19ffa8b31%26state%3D30d69d0bf32344f996c56a4cf54cba95 (...)
2020-11-25T12:36:54.641407+00:00 app[web.1]: HTTPServerRequest(protocol=‘http’, host=‘*****.herokuapp.com’, method=‘GET’, uri=‘/login?next=%2F%3Fcode%3D4bce10c0d0b19ffa8b31%26state%3D30d69d0bf32344f996c56a4cf54cba95’, version=‘HTTP/1.1’, remote_ip=‘...’)
2020-11-25T12:36:54.641408+00:00 app[web.1]: Traceback (most recent call last):
2020-11-25T12:36:54.641409+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/tornado/web.py”, line 1704, in _execute
2020-11-25T12:36:54.641410+00:00 app[web.1]: result = await result
2020-11-25T12:36:54.641411+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 241, in get
2020-11-25T12:36:54.641412+00:00 app[web.1]: user = await self.get_authenticated_user(**params)
2020-11-25T12:36:54.641413+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 108, in get_authenticated_user
2020-11-25T12:36:54.641413+00:00 app[web.1]: client_secret
2020-11-25T12:36:54.641414+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 183, in _fetch_access_token
2020-11-25T12:36:54.641414+00:00 app[web.1]: headers=self._API_BASE_HEADERS
2020-11-25T12:36:54.641481+00:00 app[web.1]: tornado.httpclient.HTTPClientError: HTTP 400: Bad Request
2020-11-25T12:36:54.642752+00:00 app[web.1]: 2020-11-25 12:36:54,642 500 GET /login?next=%2F%3Fcode%3D4bce10c0d0b19ffa8b31%26state%3D30d69d0bf32344f996c56a4cf54cba95 (...) 184.68ms

If you could set PANEL_LOG_LEVEL as an env var as well that would be helpful. I should unify the commandline arg with this but that’s not done.

It does seem like you are missing a configuration step, specifically you should provide oauth_extra_params with the URL (you can probably skip the 'server' config though unless your Okta account configures a custom authentication server:

in most other ordinary setups you will also have to provide a url via the oauth_extra_params and if you have set up a custom authentication server (i.e. not ‘default’) with Okta you must also provide ‘server’, the oauth_extra_params should then look something like this: {‘server’: ‘custom’, ‘url’: ‘dev-***.okta.com’}

Logs seem to be the same with --log-level=debug and with PANEL_LOG_LEVEL=debug. Unless I misunderstood you and I didn’t change what you’ve suggested.

The log I’ve pasted above is from a GitHub Oauth tryout and Panel documentation doesn’t mention anything about the oauth_extra_params in regards GitHub.

When I tried to achieve the same with Okta I did add oauth_extra_params but the result was the same. “Error 500 Internal server …”

So, I’m a bit confused now, but still open to all suggestions once I’m back from work in about 8 hours…

Ah, apologies, you’re right that the GitHub OAuth component doesn’t require it. My best guess now is that the redirect_url isn’t configured correctly. Could you confirm what you used for the redirect URL in GitHub and the precise URL your Heroku app is running at?

Hi again @philippjfr,

The “Authorization callback URL” in GitHub is http://***.herokuapp.com. In the Procfile I didn’t use –oauth-redirect-uri= before but after you suggested I did try and the issue is still present. Unfortunately.

I tried random websites as redirect URL’s in GitHub and they all work like a charm. On a side note, they work even without putting the –oauth-redirect-uri=*** in the Procfile.

So, back to square one, I guess.

I have a feeling that the issue lies in this section of the log:

2020-11-26T00:33:43.468483+00:00 app[web.1]: Traceback (most recent call last):
2020-11-26T00:33:43.468484+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/tornado/web.py”, line 1704, in _execute
2020-11-26T00:33:43.468485+00:00 app[web.1]: result = await result
2020-11-26T00:33:43.468485+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 241, in get
2020-11-26T00:33:43.468486+00:00 app[web.1]: user = await self.get_authenticated_user(**params)
2020-11-26T00:33:43.468487+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 108, in get_authenticated_user
2020-11-26T00:33:43.468487+00:00 app[web.1]: client_secret
2020-11-26T00:33:43.468488+00:00 app[web.1]: File “/app/.heroku/python/lib/python3.6/site-packages/panel/auth.py”, line 183, in _fetch_access_token
2020-11-26T00:33:43.468488+00:00 app[web.1]: headers=self._API_BASE_HEADERS
2020-11-26T00:33:43.468510+00:00 app[web.1]: tornado.httpclient.HTTPClientError: HTTP 400: Bad Request

Hoping, it might ring a bell, see the Procfile contents below.

web: panel serve --oauth-provider=github --oauth-key=*** --oauth-secret=*** --cookie-secret=secret --log-level=debug --address=“0.0.0.0” --port=$PORT app.py --allow-websocket-origin=***.herokuapp.com

This is the crux of it, but it really just indicates that something about the authentication request is malformed. What I should do there is try to change that line to somehow get some information about what exactly caused the request to be rejected.

I’m trying pretty much everything but no success. All sorts of combinations of CLI’s and enviromental variables, etc.

I think Panel is an amazing library, but for my current project user authentication is crucial due to sensitive employee data.

It would be nice to know if anybody else had success in deploying a Panel app on Heroku and adding OAuth. I’m sure it’s just a silly little detail, but I’m stuck at the minute.

1 Like

@danmaty

I will add a data point that I have successfully deployed a Panel app to Heroku with authentication. However, I used Flask login and custom-developed logic for user authentication and management rather than OAuth. (Not a direct answer to your question, I know, but thought it might help when assessing your options going forward.)

Hi @_jm,

Thanks for that. I’ll have a look once it’s added.

I’m open for all suggestions / solutions to add authentication for the project I’m working on now, at the same time I’d say it would benefit all current and future Panel+Heroku users to have an OAuth example at hand.

For anybody interested in a simple authentication that works on Heroku, check out the below.

Not OAuth, but gets the job done. :slight_smile:
https://github.com/bokeh/bokeh/tree/branch-2.3/examples/howto/server_auth

2 Likes

@philippjfr apologies if this issue has been solved already, but I ran into analogous problems to what @danmaty posted here.

In order to help with debugging my case, I recorded a Loom video: Loom | Free Screen & Video Recording Software | Loom

In there, my configuration is fully exposed - secrets and such - because they are throwaway credentials on a codebase that should be a minimal reproducible example, so I don’t mind showing them. (Just mentioning it here so nobody freaks out about secrets being leaked!)

What’s been frustrating for me thus far is the opacity on debugging authentication issues like this. I’m not well-versed enough to know what could be done, but I thought I would highlight that this error that @danmaty and I are encountering seem to be quite difficult to debug. Would you possibly have ideas on where we could start debugging?