sentry
sentry copied to clipboard
feat(dev-toolbar): Add organization derived API applications
Overview
To enable the dev-toolbar feature we want to allow public, third-party applications (think "Login with CodeCov" but self-serve and for all organizations) to fetch Sentry data on behalf of a Sentry user. To accommodate this I've:
- [x] Added a "scoping_organization_id" column to the
ApiTokenmodel and replica. - [x] Added a "organization_id" column to the
ApiApplicationmodel. - [x] Updated the oauth flow to set the "scoping_organization_id" on the
ApiTokenwhen an "organization_id" is present on theApiApplication. - [x] Updated the middleware responsible for gating access.
- [x] Added a resource for managing organization
ApiApplicationinstances.
Goal
The goal is to allow customers to authenticate with Sentry from a third-party origin.
How It Works
- A customer defines an ApiApplication instance tied to their organization.
- This ApiApplication contains the valid origin and redirect locations for an authorization request for that organization.
- The ApiApplication generates a client-id value. This value is public and is passed to the Javascript SDK's initializer (e.g.
sdk.init(..., client_id=xyz). - The SDK reads this client-id and initiates Sentry's oauth flow (
/oauth/authorize/) either through a hard-redirect or a pop-up window. Making sure to specify the client-id in the request parameters. - Sentry appends a url fragment containing the access token and redierects back to the requester's application.
- The token is now accessible by the third-party program and can be used to make API requests to Sentry.
CORS
To manage CORS issues, the login flow will be initiated from an iframe with a sentry.io origin.
Supporting Documentation
PRD: https://www.notion.so/sentry/FY-25-Q2-Dev-Toolbar-e2a259c063634f93a6c3d89584e812d8
Security
Public clients present two problems:
- First there is a phishing risk where a malicious third-party is given an
access_tokenand uses that token to extract sensitive data from Sentry servers. - Second there is a risk that a legitimate third-party provider may use an
access_tokento read data from other organizations.
To address these issues I've done two things:
- ApiApplications will only generate credentials if the user is a member of the organization.
- ApiTokens will be scoped to the ApiApplication's organization_id. a. Requests for data outside of the organization will be denied.
This PR has a migration; here is the generated SQL for src/sentry/hybridcloud/migrations/0017_add_public_api_applications.py src/sentry/migrations/0744_add_public_api_applications.py ()
--
-- Add field organization_id to apiapplication
--
ALTER TABLE "sentry_apiapplication" ADD COLUMN "organization_id" bigint NULL;
--
-- Add field scoping_organization_id to apitoken
--
ALTER TABLE "sentry_apitoken" ADD COLUMN "scoping_organization_id" bigint NULL;
CREATE UNIQUE INDEX CONCURRENTLY "sentry_apiapplication_organization_id_aade894f_uniq" ON "sentry_apiapplication" ("organization_id");
ALTER TABLE "sentry_apiapplication" ADD CONSTRAINT "sentry_apiapplication_organization_id_aade894f_uniq" UNIQUE USING INDEX "sentry_apiapplication_organization_id_aade894f_uniq";
CREATE INDEX CONCURRENTLY "sentry_apitoken_scoping_organization_id_b0d65472" ON "sentry_apitoken" ("scoping_organization_id");
Codecov Report
Attention: Patch coverage is 91.91919% with 8 lines in your changes missing coverage. Please review.
:white_check_mark: All tests successful. No failed tests found.
Additional details and impacted files
:loudspeaker: Thoughts on this report? Let us know!
This PR has a migration; here is the generated SQL for src/sentry/migrations/0745_add_public_api_applications.py ()
--
-- Add field organization_id to apiapplication
--
ALTER TABLE "sentry_apiapplication" ADD COLUMN "organization_id" bigint NULL;
--
-- Add field scoping_organization_id to apitoken
--
ALTER TABLE "sentry_apitoken" ADD COLUMN "scoping_organization_id" bigint NULL;
CREATE UNIQUE INDEX CONCURRENTLY "sentry_apiapplication_organization_id_aade894f_uniq" ON "sentry_apiapplication" ("organization_id");
ALTER TABLE "sentry_apiapplication" ADD CONSTRAINT "sentry_apiapplication_organization_id_aade894f_uniq" UNIQUE USING INDEX "sentry_apiapplication_organization_id_aade894f_uniq";
CREATE INDEX CONCURRENTLY "sentry_apitoken_scoping_organization_id_b0d65472" ON "sentry_apitoken" ("scoping_organization_id");
I'd be more comfortable if we put this behind a feature flag limiting it to specific organizations until we're sure the authn/authz flow is ready for production.
In a scenario where a user knows their access token has been compromised, what options do they have?
@mdtro They're supposed to be able to revoke the token with a logout request. I'll have to find exactly where that happens.
This PR has a migration; here is the generated SQL for src/sentry/migrations/0747_add_public_api_applications.py ()
--
-- Add field organization_id to apiapplication
--
ALTER TABLE "sentry_apiapplication" ADD COLUMN "organization_id" bigint NULL;
--
-- Add field scoping_organization_id to apitoken
--
ALTER TABLE "sentry_apitoken" ADD COLUMN "scoping_organization_id" bigint NULL;
CREATE UNIQUE INDEX CONCURRENTLY "sentry_apiapplication_organization_id_aade894f_uniq" ON "sentry_apiapplication" ("organization_id");
ALTER TABLE "sentry_apiapplication" ADD CONSTRAINT "sentry_apiapplication_organization_id_aade894f_uniq" UNIQUE USING INDEX "sentry_apiapplication_organization_id_aade894f_uniq";
CREATE INDEX CONCURRENTLY "sentry_apitoken_scoping_organization_id_b0d65472" ON "sentry_apitoken" ("scoping_organization_id");
🚨 Warning: This pull request contains Frontend and Backend changes!
It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently.
Have questions? Please ask in the #discuss-dev-infra channel.
@evanpurkhiser @nhsiehgit @JoshFerge Ya'll worked on the enterprise team right? Do you have any opinions on this auth flow?
This PR has a migration; here is the generated SQL for src/sentry/migrations/0748_add_public_api_applications.py ()
--
-- Add field organization_id to apiapplication
--
ALTER TABLE "sentry_apiapplication" ADD COLUMN "organization_id" bigint NULL;
--
-- Add field scoping_organization_id to apitoken
--
ALTER TABLE "sentry_apitoken" ADD COLUMN "scoping_organization_id" bigint NULL;
CREATE UNIQUE INDEX CONCURRENTLY "sentry_apiapplication_organization_id_aade894f_uniq" ON "sentry_apiapplication" ("organization_id");
ALTER TABLE "sentry_apiapplication" ADD CONSTRAINT "sentry_apiapplication_organization_id_aade894f_uniq" UNIQUE USING INDEX "sentry_apiapplication_organization_id_aade894f_uniq";
CREATE INDEX CONCURRENTLY "sentry_apitoken_scoping_organization_id_b0d65472" ON "sentry_apitoken" ("scoping_organization_id");
Bundle Report
Changes will increase total bundle size by 259 bytes :arrow_up:
| Bundle name | Size | Change |
|---|---|---|
| app-webpack-bundle-array-push | 28.69MB | 259 bytes :arrow_up: |
This pull request has gone three weeks without activity. In another week, I will close it.
But! If you comment or otherwise update it, I will reset the clock, and if you add the label WIP, I will leave it alone unless WIP is removed ... forever!
"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀