Django HRM ×
Rocket.Chat SSO
Step-by-step guide to integrate Django as an OAuth2 Provider and Rocket.Chat as the consumer. Users log in once via Django HRM and get automatic access to Rocket.Chat.
Install & Configure Django OAuth Toolkit
Backend — Django Setup
pip install django-oauth-toolkit
INSTALLED_APPS = [ # ... your apps "oauth2_provider", # ← add this ]
python manage.py migrate oauth2_provider
Configure Settings.py
Backend — Django Setup
OAUTH2_PROVIDER = { "SCOPES": { "read": "Read scope", "write": "Write scope", }, "ACCESS_TOKEN_EXPIRE_SECONDS": 36000, "REFRESH_TOKEN_EXPIRE_SECONDS": 86400, "ROTATE_REFRESH_TOKEN": True, # ← CRITICAL: disable PKCE for Rocket.Chat compatibility "PKCE_REQUIRED": False, # Allow http for local development "ALLOWED_REDIRECT_URI_SCHEMES": ["https", "http"], }
error=invalid_request&error_description=Code+challenge+required
Register URLs
Backend — Django Setup
from django.urls import path, include urlpatterns = [ path("admin/", admin.site.urls), # OAuth2 built-in endpoints — MUST be before your api urls path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")), # ← gives /o/token/ /o/authorize/ etc # Your custom endpoints path("api/v2/", include("apps.account.urls")), ]
/o/authorize/ — Authorization page/o/token/ — Token exchange/o/revoke_token/ — Token revocation/o/introspect/ — Token introspection
Create UserInfo Endpoint
Backend — Django Setup
Rocket.Chat calls this endpoint to get user data after receiving the access token. You must create this yourself.
from oauth2_provider.views import ProtectedResourceView from django.http import JsonResponse class UserInfoView(ProtectedResourceView): """ Rocket.Chat calls this with: Authorization: Bearer <token> Returns user data to create/update Rocket.Chat user profile. """ def get(self, request, *args, **kwargs): user = request.user return JsonResponse({ "sub": str(user.pk), # required — unique user ID "email": user.email, # required — for matching accounts "name": user.get_full_name() or user.username, # display name in Rocket.Chat "username": user.username, # Rocket.Chat username })
from django.urls import path from .views import UserInfoView urlpatterns = [ # ... your other urls path("o/userinfo/", UserInfoView.as_view(), name="userinfo"), ]
sub as the unique identifier to match/create users. Without it the integration will fail silently.
Create OAuth Application in Django Admin
Backend — Django Admin
Go to http://your-domain/admin/oauth2_provider/application/add/
| Field | Value | Why |
|---|---|---|
| Name | Rocket.Chat SSO | Any descriptive name |
| Client Type | Confidential | Server-to-server, secret is kept safe |
| Authorization Grant Type | Authorization code | Standard OAuth2 web flow |
| Redirect URIs | https://your_company_domain.com/_oauth/hrm | Must match Rocket.Chat callback exactly |
| Hash Client Secret | ☐ UNCHECK | Keep plain so you can copy it |
| Algorithm | No OIDC support | Disables PKCE requirement |
python manage.py shell from oauth2_provider.models import Application import secrets app = Application.objects.get(name="Rocket.Chat SSO") new_secret = secrets.token_urlsafe(40) print("COPY THIS:", new_secret) # ← copy immediately app.client_secret = new_secret app.hash_client_secret = False app.save() # Verify app.refresh_from_db() print("Saved:", app.client_secret == new_secret) # must be True
Configure Rocket.Chat OAuth
Rocket.Chat — Admin Panel
Go to Rocket.Chat Admin → OAuth → Add Custom → name it hrm
| Field | Value |
|---|---|
| Enable | True |
| URL | https://api.your_company_site.com |
| Token Path | /o/token/ |
| Token Sent Via | Header |
| Identity Token Sent Via | Header |
| Identity Path | /api/v2/o/userinfo/ |
| Authorize Path | /o/authorize/ |
| Scope | read write |
| Param Name for access token | access_token |
| Id | KEf3f5N4JiTg9fuyRU96zcX882ZSR2Cwihbmbkfv |
| Secret | your_plain_secret_from_step5 |
| Login Style | Redirect |
| Username field | username |
| Email field | |
| Name field | name |
| Merge Users | True |
Test The Complete Flow
End-to-End — Manual Test
# First get a token via password grant (for testing only) curl -X POST https://api.your_company_site.com/o/token/ \ -d "grant_type=password" \ -d "username=admin@gmail.com" \ -d "password=your_password" \ -d "client_id=SFsdfsdfsdfdsfsdfsdfdsfwerwerwerwerwerwe" \ -d "client_secret=your_plain_secret" # Then test userinfo with returned access_token curl https://api.your_company_site.com/api/v2/o/userinfo/ \ -H "Authorization: Bearer ACCESS_TOKEN_HERE"
{"sub": "42", "email": "admin@gmail.com", "name": "...", "username": "..."}
Frontend — Login Button
Frontend — Any Framework
If you have a custom frontend (React, Vue, etc.) that needs to trigger the OAuth flow:
// Build the authorize URL and redirect user function loginWithHRM() { const params = new URLSearchParams({ response_type: "code", client_id: "KEf3f5N4JiTg9fuyRU96zcX882ZSR2Cwihbmbkfv", redirect_uri: "https://your_company_site.com/_oauth/hrm", scope: "read write", state: generateState(), // random string for CSRF protection }); window.location.href = `https://api.your_company_site.com/o/authorize/?${params}`; } function generateState() { return Math.random().toString(36).substring(2, 15); }
Frontend — Handle Callback
Frontend — Custom App Only
// On your redirect_uri page, extract the code const params = new URLSearchParams(window.location.search); const code = params.get("code"); const state = params.get("state"); // Exchange code for token via your backend const response = await fetch("/api/v2/account/oauth/callback/", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code, state }), }); const { access_token } = await response.json(); localStorage.setItem("token", access_token); window.location.href = "/dashboard";
import requests from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import AllowAny class OAuthCallbackView(APIView): permission_classes = [AllowAny] def post(self, request): code = request.data.get("code") # Exchange code for token token_response = requests.post( "https://api.your_company_site.com/o/token/", data={ "grant_type": "authorization_code", "code": code, "redirect_uri": "https://your-frontend.com/callback", "client_id": "KEf3f5N4JiTg9fuyRU96zcX882ZSR2Cwihbmbkfv", "client_secret": "your_plain_secret", } ) return Response(token_response.json())
Common Errors & Fixes
Troubleshooting Reference
PKCE_REQUIRED: False in OAUTH2_PROVIDER settingspath("o/", include("oauth2_provider.urls", namespace="oauth2_provider"))Authorization: Bearer <token>, check token expiryreturn self.name or f"Model #{self.pk}" in every modelIntegration Checklist
Click to mark done