Social login for Django REST Framework - with account linking, JWT tokens, and room to grow.
django-social-auth-rest lets your users sign in with their social accounts (Google, GitHub) and returns JWT tokens your frontend can use right away. It also handles connecting and disconnecting those social accounts after the fact.
Currently supported providers: Google, GitHub
More providers are coming soon.
The following packages are installed automatically:
djangorestframework-simplejwtgoogle-authrequestspip install django-social-auth-rest
INSTALLED_APPS# settings.py
INSTALLED_APPS = [
# ...
"rest_framework",
"django_social_auth_rest",
]
# settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
}
# settings.py
from datetime import timedelta
SIMPLE_JWT = {
"AUTH_HEADER_TYPES": ("Bearer",),
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
}
Add credentials only for the providers you want to use. Providers without credentials are automatically disabled - their endpoints will not be available.
# settings.py
# GitHub (requires both values)
GITHUB_CLIENT_ID = "your-github-client-id"
GITHUB_CLIENT_SECRET = "your-github-client-secret"
# Google (requires only the client ID)
GOOGLE_CLIENT_ID = "your-google-client-id"
# add more providers here as needed
See the Provider Guides section for where to get these credentials.
Include the base URL module plus each provider you want to enable:
# urls.py
from django.urls import path, include
urlpatterns = [
path("api/social-auth/", include("django_social_auth_rest.urls")),
path("api/social-auth/", include("django_social_auth_rest.urls.github")),
path("api/social-auth/", include("django_social_auth_rest.urls.google")),
# add more providers here as needed
]
You only need to include a provider’s URL module if you’re using that provider. See the Provider Guides section for details on each provider’s endpoints.
python manage.py migrate
These settings have sensible defaults and do not need to be changed unless you have specific requirements.
| Setting | Default | What It Does |
|---|---|---|
SOCIAL_AUTH_THROTTLE_RATE |
"10/minute" |
Limits how many auth requests a user can make per minute |
SOCIAL_AUTH_STATE_SALT |
"social-auth-state-salt" |
Salt value used to sign OAuth state tokens - change this in production |
SOCIAL_AUTH_STATE_MAX_AGE |
300 |
How long (in seconds) a state token stays valid before expiring |
SOCIAL_AUTH_USER_DELETED_FIELD |
None |
Name of a boolean field on your user model that marks soft-deleted accounts |
# settings.py
GITHUB_CLIENT_ID = "your-github-client-id"
GITHUB_CLIENT_SECRET = "your-github-client-secret"
# urls.py
from django.urls import path, include
urlpatterns = [
path("api/social-auth/", include("django_social_auth_rest.urls.github")),
]
GitHub uses the standard OAuth 2.0 authorization code flow. Your frontend redirects the user to GitHub, which then redirects back with a temporary code. That code is sent to your backend to complete the login.
A signed state token is used to prevent CSRF attacks - your frontend must request one before starting the flow and include it throughout.
1. Frontend requests a state token → GET /api/social-auth/github/state/
2. Frontend redirects user to GitHub with client_id and state token
3. User authorizes on GitHub, gets redirected back with a code and state
4. Frontend sends code + state to POST /api/social-auth/github/login/
5. Backend validates the state, exchanges the code, and returns JWT tokens
Get a state token (required before starting the OAuth flow)
GET /api/social-auth/github/state/
Response:
{
"state": "<SIGNED_STATE_TOKEN>"
}
Login
POST /api/social-auth/github/login/
Content-Type: application/json
{
"code": "<AUTHORIZATION_CODE>",
"state": "<SIGNED_STATE_TOKEN>"
}
Response:
{
"access": "<JWT_ACCESS_TOKEN>",
"refresh": "<JWT_REFRESH_TOKEN>"
}
Link account (requires authentication)
POST /api/social-auth/github/link/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Content-Type: application/json
{
"code": "<AUTHORIZATION_CODE>",
"state": "<SIGNED_STATE_TOKEN>"
}
Returns 204 No Content on success.
Unlink account (requires authentication)
POST /api/social-auth/github/unlink/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Returns 204 No Content on success.
# settings.py
GOOGLE_CLIENT_ID = "your-google-client-id"
# urls.py
from django.urls import path, include
urlpatterns = [
path("api/social-auth/", include("django_social_auth_rest.urls.google")),
]
Google uses an ID token flow. Your frontend handles the Google sign-in and receives an ID token from Google. It sends that token to your backend, which validates it and issues JWT tokens.
1. User signs in with Google on your frontend
2. Frontend receives a Google ID token
3. Frontend sends the token to POST /api/social-auth/google/login/
4. Backend validates the token with Google
5. Backend returns JWT access and refresh tokens
Login
POST /api/social-auth/google/login/
Content-Type: application/json
{
"token": "<GOOGLE_ID_TOKEN>"
}
Response:
{
"access": "<JWT_ACCESS_TOKEN>",
"refresh": "<JWT_REFRESH_TOKEN>"
}
Link account (requires authentication)
POST /api/social-auth/google/link/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Content-Type: application/json
{
"token": "<GOOGLE_ID_TOKEN>"
}
Returns 204 No Content on success.
Unlink account (requires authentication)
POST /api/social-auth/google/unlink/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Returns 204 No Content on success.
Returns a list of all enabled providers and whether the current user has connected each one.
Requires authentication.
GET /api/social-auth/linked-accounts/
Authorization: Bearer <JWT_ACCESS_TOKEN>
Response:
{
"providers": [
{
"label": "Google",
"is_linked": true
},
{
"label": "GitHub",
"is_linked": false
}
// more providers as configured
]
}
If your app uses soft deletion (marking users as deleted rather than removing them from the database), you can block deleted accounts from signing in.
Set SOCIAL_AUTH_USER_DELETED_FIELD to the name of the boolean field on your user model:
# settings.py
SOCIAL_AUTH_USER_DELETED_FIELD = "is_deleted"
Example user model:
class User(AbstractUser):
is_deleted = models.BooleanField(default=False)
When this is configured, any user with is_deleted = True will be blocked from logging in, linking, or creating a new account through social auth.
The package sends Django signals for key events. You can connect to these to run your own code - for example, sending a welcome email when a new user registers.
| Signal | When it fires |
|---|---|
new_user_registered |
A new account is created for the first time via social auth |
login_successful |
A user successfully signs in |
link_account_successful |
A social account is linked to a user |
unlink_account_successful |
A social account is removed from a user |
All signals include these keyword arguments: request, user, provider.
Example:
from django.dispatch import receiver
from django_social_auth_rest.signals import new_user_registered
@receiver(new_user_registered)
def on_new_user(sender, request, user, provider, **kwargs):
print(f"New user {user.email} joined via {provider}")
# send welcome email, create profile, etc.
Contributions are welcome. If you find a bug or want to suggest an improvement, please open an issue first so we can discuss it.
More authentication providers are planned - if you’d like to add one, open an issue to coordinate.
MIT - see LICENSE for details.