Skip to content
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

Backchannel Logout #3111

Open
jharmon96 opened this issue Jun 7, 2022 · 3 comments
Open

Backchannel Logout #3111

jharmon96 opened this issue Jun 7, 2022 · 3 comments

Comments

@jharmon96
Copy link

jharmon96 commented Jun 7, 2022

Are there any plans to add backchannel logouts to this library?

I have a collection of applications that use one oidc provider. When a user logs out of one app I'd like for them to be logged out of the others.

https://openid.net/specs/openid-connect-backchannel-1_0.html#BCRequest

For reference, this is what I've done in the time being to get this to work with Keycloak:

## Keycloak Backchannel Logout
from allauth.socialaccount.models import SocialAccount
from django.http import HttpResponse, HttpRequest
from django.views.decorators.csrf import csrf_exempt
from django.contrib.sessions.models import Session
from importlib import import_module
import jwt

def init_session(session_key):
    """
    Initialize same session as done for ``SessionMiddleware``.
    """
    engine = import_module(settings.SESSION_ENGINE)
    return engine.SessionStore(session_key)

@csrf_exempt
def backchannel_logout(request):
    ''' Keycloak is set to send a POST request to this route if a user
        logs out via another application, such as Superset. 
        This function will ensure the user is logged out of this app
        as well.
    '''
    # First run a bunch of checks to make sure that the request is valid
    if request.method != 'POST': return HttpResponse(status=405)
    if settings.KEYCLOAK_PUBLIC_KEY == None: return HttpResponse(status=501)
    t = request.POST['logout_token']
    try:
        decoded = jwt.decode(t, key=settings.KEYCLOAK_PUBLIC_KEY, algorithms=['RS256', ], audience=settings.KEYCLOAK_APPS)
        uid = decoded['sub']
        aud = decoded['aud']
    except Exception as e:
        logger.error(f"Backchannel logout failed: {e}")
        return HttpResponse(406)
    if not SocialAccount.objects.filter(uid=uid).exists(): 
        logger.warning(f"User {uid} does not exist in this application.")
        return HttpResponse(406)

    # If we made it this far, then the request checks out. Continue to log user out.
    from django.contrib.auth import logout
    user = SocialAccount.objects.get(uid=uid).user
    sessions = [s for s in Session.objects.all() if s.get_decoded().get('_auth_user_id') == str(user.id)]
    request = HttpRequest()

    for session in sessions:
        request.session = init_session(session.session_key)
        logout(request)
    
    if len(sessions) != 0: logger.debug("{user.username} has been logged out by {aud}")

    return HttpResponse(status=200)
@shawnngtq
Copy link

@jharmon96 ,

Side question, do you have any guide / article / blog about best practice of using django / allauth with keycloak?

I just created a keycloak vanilla client for django app, without client scopes / groups. Quite sure I should, but 0 clue 😁

@pennersr
Copy link
Owner

  SOCIALACCOUNT_PROVIDERS = {
      "openid_connect": {
          "APPS": [
              {
                  "provider_id": "keycloak",
                  "name": "Keycloak",
                  "client_id": "<insert-id>",
                  "secret": "<insert-secret>",
                  "settings": {
                      "server_url": "http://keycloak:8080/realms/master/.well-known/openid-configuration",
                  },
              }
          ]
      }
  }

@shawnngtq
Copy link

shawnngtq commented Sep 17, 2023

@pennersr , I managed to get it working, allauth is flawless here 😁

What I'm unsure of is the keycloak side

image

There is a concept of client scopes and groups that you can attach additional attributes. It's complex and depends on user experience rather than documentation. Was hoping to hear how others django users are doing these.

Just created a post on Django forum too:

https://forum.djangoproject.com/t/django-keycloak-best-practice/23924

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants