feat(oauth): Add PKCE support for OAuth2 authorization code flow
Implements RFC 7636 Proof Key for Code Exchange (PKCE) to protect OAuth2 authorization code grants from interception attacks. Adds code_challenge and code_challenge_method support to the authorize endpoint, and validates code_verifier in the token endpoint. Supports both S256 and plain methods.
Refs #99002
Replaces #99452
This PR has a migration; here is the generated SQL for src/sentry/migrations/1012_add_pkce_to_apigrant.py
for 1012_add_pkce_to_apigrant in sentry
--
-- Add field code_challenge to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge" varchar(128) NULL;
--
-- Add field code_challenge_method to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge_method" varchar(10) NULL;
:x: 1 Tests Failed:
| Tests completed | Failed | Passed | Skipped |
|---|---|---|---|
| 30800 | 1 | 30799 | 246 |
View the top 1 failed test(s) by shortest run time
tests.sentry.web.frontend.test_oauth_token.OAuthTokenCodeTest::test_inactive_application_rejects_token_creationStack Traces | 0.395s run time
#x1B[1m#x1B[.../web/frontend/test_oauth_token.py#x1B[0m:334: in test_inactive_application_rejects_token_creation assert not ApiGrant.objects.filter(id=self.grant.id).exists() #x1B[1m#x1B[31mE assert not True#x1B[0m #x1B[1m#x1B[31mE + where True = <bound method QuerySet.exists of <BaseQuerySet [<ApiGrant at 0x7f28763612e0: id=63>]>>()#x1B[0m #x1B[1m#x1B[31mE + where <bound method QuerySet.exists of <BaseQuerySet [<ApiGrant at 0x7f28763612e0: id=63>]>> = <BaseQuerySet [<ApiGrant at 0x7f2876360ec0: id=63>]>.exists#x1B[0m #x1B[1m#x1B[31mE + where <BaseQuerySet [<ApiGrant at 0x7f2876360ec0: id=63>]> = <bound method QuerySet.filter of <sentry.db.models.manager.base.BaseManager object at 0x7f29627181a0>>(id=63)#x1B[0m #x1B[1m#x1B[31mE + where <bound method QuerySet.filter of <sentry.db.models.manager.base.BaseManager object at 0x7f29627181a0>> = <sentry.db.models.manager.base.BaseManager object at 0x7f29627181a0>.filter#x1B[0m #x1B[1m#x1B[31mE + where <sentry.db.models.manager.base.BaseManager object at 0x7f29627181a0> = ApiGrant.objects#x1B[0m #x1B[1m#x1B[31mE + and 63 = <ApiGrant at 0x7f28763610d0: id=63>.id#x1B[0m #x1B[1m#x1B[31mE + where <ApiGrant at 0x7f28763610d0: id=63> = <sentry.testutils.silo.OAuthTokenCodeTest testMethod=test_inactive_application_rejects_token_creation>.grant#x1B[0m
To view more test analytics, go to the Test Analytics Dashboard 📋 Got 3 mins? Take this short survey to help us improve Test Analytics.
This PR has a migration; here is the generated SQL for src/sentry/migrations/1013_add_pkce_to_apigrant.py
for 1013_add_pkce_to_apigrant in sentry
--
-- Add field code_challenge to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge" varchar(128) NULL;
--
-- Add field code_challenge_method to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge_method" varchar(10) NULL;
This PR has a migration; here is the generated SQL for src/sentry/migrations/1014_add_pkce_to_apigrant.py
for 1014_add_pkce_to_apigrant in sentry
--
-- Add field code_challenge to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge" varchar(128) NULL;
--
-- Add field code_challenge_method to apigrant
--
ALTER TABLE "sentry_apigrant" ADD COLUMN "code_challenge_method" varchar(10) NULL;
i think we're good to go