Find OAuth handlers that will break when users rename their identifier.
Project description
authdrift
Find OAuth handlers that will break when users rename their Gmail.
On 31 March 2026, Google began letting users rename their primary Gmail address. Every OAuth integration that uses email as the user lookup key will silently create a duplicate account when a user renames. Most do.
authdrift is a static analysis tool that scans your codebase for the exact patterns that explode on a Gmail rename — and on the ~0.04% baseline sub-claim drift Truffle Security documented in January 2025.
Install
pip install authdrift
Requires semgrep (installed automatically).
Use
authdrift scan ./
Example output:
src/auth/google.ts
12:18 WARNING oauth-passport-email-as-primary-key
This OAuth handler is using `profile.emails[0].value` as a user lookup key.
When a user renames their Gmail address, this lookup will fail and your
application will silently create a duplicate user record.
Fix: use `profile.id` (the OIDC `sub` claim) as the immutable primary key.
JSON output for CI:
authdrift scan ./ --json
Why this matters
Atlassian's own KB confirms that SCIM email changes create duplicate Atlassian Cloud accounts. Google's developer documentation acknowledges that revoke + reauth produces duplicate accounts. The cascade is documented; the fix is not deployed.
authdrift flags the exact code patterns that produce phantom users after a rename event. Three rules, narrowly scoped, designed to slot into CI alongside semgrep, trufflehog, and gitleaks without producing noise.
What it catches today
- Passport.js handlers using
profile.emails[0].valueas a user lookup key (passport-google-oauth20,passport-google-oauth2) - NextAuth
signIncallbacks resolving users byuser.emailagainst Prisma - Python (Django / SQLAlchemy) handlers querying by
userinfo['email']from Google's userinfo response
What it deliberately does NOT do
- Flag every reference to
emailin an OAuth file. The rules require the email value to be used as a lookup key, not just read or logged. - Flag handlers that key on
sub/profile.idand use email only as a contact attribute. - Auto-fix anything. Read-only by design.
Roadmap
- More OAuth library coverage (lucia-auth, authlib, omniauth, Clerk, Supabase Auth, Firebase Auth)
- A
--fixmode that suggests thesub-keyed equivalent - A hosted scan for organisations that can't run a CLI
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file authdrift-0.1.0.tar.gz.
File metadata
- Download URL: authdrift-0.1.0.tar.gz
- Upload date:
- Size: 5.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f307e8d502d0cacd26709d5efaeaded1eae11a872da5353df192fc72de4ea02
|
|
| MD5 |
442077d4eb0763ae3547d59563e36b6d
|
|
| BLAKE2b-256 |
21ea69d253f0c524a9cc762804d4317df425222566cee800e3a4f0ebc2f5ca9b
|
File details
Details for the file authdrift-0.1.0-py3-none-any.whl.
File metadata
- Download URL: authdrift-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
184235c73dcc25a3ea1b8f5a7d11a7a8b2ccab6f8cfb044f05e6581b756131f5
|
|
| MD5 |
b18436456c440061aa1226239424560a
|
|
| BLAKE2b-256 |
78d013defebef5e2b18fdbf03d7f3480a933bca38762b3c59db107873a7d18b7
|