12
113
Fork
You've already forked django-allauth
149

Support encrypted storage of SocialApp.client_secret credentials #4748

Open
opened 2026年05月29日 05:30:06 +02:00 by ArnavBallinCode · 2 comments

Problem

allauth.socialaccount.models.SocialApp.secret currently stores OAuth client secrets in plaintext in the database.

Example:

SocialApp.objects.create(
 provider="google",
 client_id="...",
 secret="super-secret-client-secret"
)

The secret is directly readable by anyone with database access.

For many deployments this may be acceptable because the application must eventually access the plaintext secret to perform OAuth flows.

However, in multi-tenant SaaS deployments, OAuth credentials may be supplied by customers rather than platform operators.

Examples:

  • Event organizers configuring their own Google OAuth application
  • Organizations configuring their own Wikimedia OAuth application
  • Enterprise customers configuring their own identity provider

In these cases, database administrators and platform operators can view customer-owned OAuth client secrets directly.

Question

Is plaintext storage of SocialApp.secret the intended design?

If so, what is the recommended approach for applications that want to:

  • Encrypt OAuth client secrets at rest
  • Support encryption key rotation
  • Prevent accidental exposure in admin interfaces
  • Remain compatible with future django-allauth upgrades

Current Situation

We are evaluating a solution that encrypts SocialApp.secret before persistence and transparently decrypts it when allauth accesses the provider configuration.

One implementation approach involves overriding SocialAccountAdapter.list_apps() and decrypting secrets at runtime.

However, this requires modifying behavior around the SocialApp model and potentially performing schema changes on the socialaccount_socialapp table.

Before proceeding further, we would like to understand whether django-allauth already provides a supported extension point or recommended pattern for protecting stored OAuth client secrets.

Possible Approaches

Some possibilities could include:

  • First-class encrypted field support
  • A pluggable secret storage backend
  • Hooks for secret serialization/deserialization
  • Official guidance on implementing encrypted storage externally

Expected Behavior

Ideally, applications should have a supported way to protect OAuth client secrets at rest while remaining compatible with future django-allauth releases.

Could the maintainers clarify:

  1. Whether plaintext storage is an intentional design decision.
  2. Whether encrypted storage is considered within scope for django-allauth.
  3. What extension points are recommended for applications that need stronger secret protection.
## Problem `allauth.socialaccount.models.SocialApp.secret` currently stores OAuth client secrets in plaintext in the database. Example: ```python SocialApp.objects.create( provider="google", client_id="...", secret="super-secret-client-secret" ) ``` The secret is directly readable by anyone with database access. For many deployments this may be acceptable because the application must eventually access the plaintext secret to perform OAuth flows. However, in multi-tenant SaaS deployments, OAuth credentials may be supplied by customers rather than platform operators. Examples: - Event organizers configuring their own Google OAuth application - Organizations configuring their own Wikimedia OAuth application - Enterprise customers configuring their own identity provider In these cases, database administrators and platform operators can view customer-owned OAuth client secrets directly. ## Question Is plaintext storage of `SocialApp.secret` the intended design? If so, what is the recommended approach for applications that want to: - Encrypt OAuth client secrets at rest - Support encryption key rotation - Prevent accidental exposure in admin interfaces - Remain compatible with future django-allauth upgrades ## Current Situation We are evaluating a solution that encrypts `SocialApp.secret` before persistence and transparently decrypts it when allauth accesses the provider configuration. One implementation approach involves overriding `SocialAccountAdapter.list_apps()` and decrypting secrets at runtime. However, this requires modifying behavior around the `SocialApp` model and potentially performing schema changes on the `socialaccount_socialapp` table. Before proceeding further, we would like to understand whether django-allauth already provides a supported extension point or recommended pattern for protecting stored OAuth client secrets. ## Possible Approaches Some possibilities could include: - First-class encrypted field support - A pluggable secret storage backend - Hooks for secret serialization/deserialization - Official guidance on implementing encrypted storage externally ## Expected Behavior Ideally, applications should have a supported way to protect OAuth client secrets at rest while remaining compatible with future django-allauth releases. Could the maintainers clarify: 1. Whether plaintext storage is an intentional design decision. 2. Whether encrypted storage is considered within scope for django-allauth. 3. What extension points are recommended for applications that need stronger secret protection.

I also had the same question

I also had the same question

You can avoid storing the SocialApp configuration in the database altogether by moving the apps into the settings (SOCIALACCOUNT_PROVIDERS). If that is not an option for your use case, then indeed currently these are stored unencrypted. What we can do there to improve is to offer encrypt()/decrypt() adapter methods (similar to what allauth.mfa has) and store/retrieve the secret using those methods. Then, in your project, you can override and choose whatever encryption you would like.

You can avoid storing the `SocialApp` configuration in the database altogether by moving the apps into the settings (``SOCIALACCOUNT_PROVIDERS``). If that is not an option for your use case, then indeed currently these are stored unencrypted. What we can do there to improve is to offer `encrypt()/decrypt()` adapter methods (similar to what `allauth.mfa` has) and store/retrieve the secret using those methods. Then, in your project, you can override and choose whatever encryption you would like.
Sign in to join this conversation.
No Branch/Tag specified
main
fix/account-middleware-reauth-exc-vs-api
65.12.x
65.11.x
feat/openid-connect-id-token
fix/phone-vs-social-signup
65.8.x
feat/idp
feat/resend-code-or-change
fix/phone-signup-conflict
feat/phone
fix/headless-email-verification-by-code
fix/a11y
feat/facebook-limited-login
fix/headless-only-connect-reauth
fix/email-added-vs-code-verification
feat/login-required-middleware
0.63.x
refactor-unique-true-field
0.62.x
0.57.x
0.60.x
0.55.x
feat-metamask
65.18.0
65.17.0
65.16.1
65.16.0
65.15.1
65.15.0
65.14.3
65.14.2
65.14.1
65.14.0
65.13.1
65.13.0
65.12.1
65.12.0
65.11.2
65.11.1
65.11.0
65.10.0
65.9.0
65.8.1
65.8.0
65.7.0
65.6.0
65.5.0
65.4.1
65.4.0
65.3.1
65.3.0
65.2.0
65.1.0
65.0.2
65.0.1
65.0.0
64.2.1
64.2.0
64.1.0
64.0.0
0.63.6
0.63.5
0.63.4
0.63.3
0.63.2
0.63.1
0.63.0
0.62.1
0.62.0
0.57.2
0.61.1
0.57.1
0.61.0
0.60.1
0.60.0
0.59.0
0.58.2
0.58.1
0.58.0
0.57.0
0.56.1
0.56.0
0.55.2
0.55.1
0.55.0
0.54.0
0.53.1
0.53.0
0.52.0
0.51.0
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.0
0.42.0
0.41.0
0.40.0
0.39.1
0.39.0
0.38.0
0.37.1
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.1
0.26.0
0.25.2
0.25.1
0.25.0
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.0
0.16.1
0.16.0
0.15.0
0.14.2
0.14.1
0.14.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.0
0.8.3
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
allauth/django-allauth#4748
Reference in a new issue
allauth/django-allauth
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?