Twitter and Facebook auth in Dash?

I’m looking to create a personalized dashboard based on Plotly Dash using the Twitter and Facebook APIs. Would it be possible to get social-auth functionality on Dash?

You could create your own component in React or see if there are any existing adaptable packages on npm:


1 Like

Sorry I just bumped into this question, may be is relevant to what I am looking for…

If my understanding is correct, this can be used as a way to authenticate a user based in the existing profile in Facebook or twitter?, is like when there is a new window asking for the username and password of Facebook?

I am interested in developing a survey and to make sure the person is unique, the best way is to allow them to enter login details of their existing Facebook, in that way they are an authentic person and not a fake surveys

I have been using Keycloak for this purpose. In my case, it was for LDAP authentication, but it supports social networks too (Google, Github, FaceBook, Twitter, …).

https://www.keycloak.org/

It requires that you run a Keycloak server though, which might or might not be an issue depending on your hosting achitecture.

Hi Emil

Interesting, but how with be the integration in Dash, is there any example code?

Cheers

I have wrapped up a small package and pushed it to pypi,

I included a MWE to demonstrate the usage,

import sys

import dash
import dash_core_components as dcc
import dash_html_components as html

from dash.dependencies import Input, Output
from flask import Flask, session
from flask_keycloak import FlaskKeycloak

# Read config path from cmd if provided.
config_path = None if len(sys.argv) < 2 else sys.argv[1]
# Setup server.
server = Flask(__name__)
FlaskKeycloak.from_kc_oidc_json(server, "http://localhost:5000/", config_path=config_path)
# Setup dash app.
app = dash.Dash(__name__, server=server)
app.layout = html.Div(id="main", children=[html.Div(id="greeting"), dcc.LogoutButton(logout_url='/logout')])


@app.callback(
    Output('greeting', 'children'),
    [Input('main', 'children')])
def update_greeting(input_value):
    user = session["user"]
    return "Hello {}".format(user['preferred_username'])


if __name__ == '__main__':
    app.run_server(port=5000)

The magic happens in this line,

FlaskKeycloak.from_kc_oidc_json(server, "http://localhost:5000/", config_path=config_path)

which injects the keycloak authentication middleware into the flask server. What is does is,

  • Check if a user is logged in (by inspecting session content)
    -> if not, redirect to login page; otherwise let the user access the page
  • When login is clicked, the credentials are authenticated via the Keycloak server
    -> if the credentials are OK, a session cookie is set and the user is redirected to the redirect url; otherwise the user is redirected back to the login page

Hence the user information can be accessed in callback from the session context as

user = session["user"]

Note that i have not implemented support for the advanced authorization functionality that Keycloak implements.

1 Like

Hi Emil

I have been figuring out how keycloak can be implemented and I am able to run it locally. The issue is with the hosting architecture which will not be local.
I have consulted the support team for the server and they indicate that keycloak can’t be implemented on their servers.

Is there any other alternative that can provide this functionality, specifically dealing with authenticating a user via facebook account?

Cheers

Since Keycloak worked great for my use case, i didn’t look much into other options. If you cannot find any Dash package that can do the job, you can look for Flask packages (or react, as suggested previously). However, they might need some tailoring (similar to the dash-keycloak package) to match your use case.

Can you share package documentation? @Emil

I have only written what is on pypi so far. What kind of documentation do you need?

@Emil
First off, thank you for creating this package.

Can you specify what you mean by “advanced authorization functionality”? What exactly is implemented and what not?

Once authorized, the current implementation injects access_token (as token) along with the userinfo and introspect information (fetched via python-keycloak) into the session. Hence you can check if a user is authorized, what their username is, and a few other things (the introspect information holds e.g. the roles of the user).

Keycloak itself can do a lot more than this (groups, resource management, …), but that i haven’t looked into. The above was enough for my usecase.

1 Like

@Emil :
I’m using your MWE from above, but cannot get it to run.
I get the following error:

Traceback (most recent call last):
  File "test1.py", line 12, in <module>
    FlaskKeycloak.from_kc_oidc_json(server, "http://localhost:8080/", config_path=Path("./keycloak.json"))
  File "/home/<username>/.miniconda3/envs/pp/lib/python3.8/site-packages/flask_keycloak/core.py", line 125, in from_kc_oidc_json
    client_secret_key=config_data["credentials"]["secret"],
KeyError: 'credentials'

If i authentificate manually using python-keycloak i don’t run into issues, i can see my token and userinfo:

In [13]: userinfo
Out[13]:
{'sub': '6aedefd7-693d-4c0c-8cd5-714d2f91eca6',
 'email_verified': False,
 'preferred_username': 'testuser'}

I think it is a trivial error, but i would be glad for a little nudge, because keycloak and authentification are new topics for me.

Could you paste the content of your keycloak.json file?

I added the hostname manually, i didn’t find a field in keycloak which adds it. The settings i changed are sparse, since i don’t know what most of them do (yet).

{
  "hostname": "https://127.0.0.1:8080",
  "realm": "Demo",
  "auth-server-url": "http://localhost:8080/auth/",
  "ssl-required": "external",
  "resource": "dash-keycloak",
  "public-client": true,
  "confidential-port": 0
}

As notes in the example, it is expected that the Access Type is set to Confidential,

After setting up the server, create a client for the application. Set “Access Type” to “confidential”, set the valid redirect URIs (mandatory), and click “Save”. Go to “Installation”, select “Keycloak OIDC JSON” as “Format Option” and download the file.

It seems from your json content that you have instead set the Access Type to Public, and therefore the code fails.

1 Like

Thank you @Emil. I could do this following your guide and everything works well. BTW, have you tried using Keycloack in production? I’d like to understand how you managed different database for avoiding a single point of failure.

Great to hear! Unfortunately, i haven’t got any experience with Keycloak in a “real” production environment. My Dash apps are hosted on an internal company VM, which also host the Keycloak server.

@Emil I see! Thank you. How do you then avoid a “single point of failure” i.e. what happens when for some unfortunate reason, that company VM is lost?

Also, do you think the package you created is production-ready?

Each of my services (Dash apps, Keycloak server, Terracotta backends, etc.) are wrapped in a Docker container. If a container crashes, it is restarted automatically. If the VM dies, it will be automatically restored by IT, and the Docker containers will spin up again as soon as the VM comes online.

I have been using the package for a few months without issues, so I consider it to be stable.

1 Like