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.
Metadata
Release files for authdrift 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| authdrift-0.1.0.tar.gz | 5.6 kB | Without provenance | Details for authdrift-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| authdrift-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for authdrift-0.1.0-py3-none-any.whl |
Total release size: 11.7 kB
Release files / authdrift-0.1.0.tar.gz
| Download URL | authdrift-0.1.0.tar.gz |
|---|---|
| Size | 5.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7f307e8d502d0cacd26709d5efaeaded1eae11a872da5353df192fc72de4ea02
|
|
BLAKE2b-256 checksum How to use checksums |
21ea69d253f0c524a9cc762804d4317df425222566cee800e3a4f0ebc2f5ca9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / authdrift-0.1.0-py3-none-any.whl
| Download URL | authdrift-0.1.0-py3-none-any.whl |
|---|---|
| Size | 6.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
184235c73dcc25a3ea1b8f5a7d11a7a8b2ccab6f8cfb044f05e6581b756131f5
|
|
BLAKE2b-256 checksum How to use checksums |
78d013defebef5e2b18fdbf03d7f3480a933bca38762b3c59db107873a7d18b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Security for authdrift 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.