From 40e5ad549905744083fa6ca0c9bcee450fff0850 Mon Sep 17 00:00:00 2001 From: Asher Date: Mon, 25 Mar 2024 11:52:22 -0800 Subject: [PATCH] feat: make OAuth2 provider not enterprise-only (#12732) --- coderd/coderd.go | 56 +++++++++++++ .../identityprovider/authorize.go | 0 .../identityprovider/middleware.go | 0 .../identityprovider/revoke.go | 0 .../identityprovider/secrets.go | 0 .../identityprovider/tokens.go | 0 {enterprise/coderd => coderd}/oauth2.go | 25 ++---- {enterprise/coderd => coderd}/oauth2_test.go | 81 +++++++------------ codersdk/deployment.go | 4 - enterprise/coderd/coderd.go | 65 --------------- site/src/api/typesGenerated.ts | 2 - .../OAuth2AppsSettingsPage.tsx | 5 -- .../OAuth2AppsSettingsPageView.stories.tsx | 10 +-- .../OAuth2AppsSettingsPageView.tsx | 12 --- 14 files changed, 92 insertions(+), 168 deletions(-) rename {enterprise/coderd => coderd}/identityprovider/authorize.go (100%) rename {enterprise/coderd => coderd}/identityprovider/middleware.go (100%) rename {enterprise/coderd => coderd}/identityprovider/revoke.go (100%) rename {enterprise/coderd => coderd}/identityprovider/secrets.go (100%) rename {enterprise/coderd => coderd}/identityprovider/tokens.go (100%) rename {enterprise/coderd => coderd}/oauth2.go (94%) rename {enterprise/coderd => coderd}/oauth2_test.go (94%) diff --git a/coderd/coderd.go b/coderd/coderd.go index 2c6367c58a..eaeb46e46d 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -689,6 +689,34 @@ func New(options *Options) *API { }) } + // OAuth2 linking routes do not make sense under the /api/v2 path. These are + // for an external application to use Coder as an OAuth2 provider, not for + // logging into Coder with an external OAuth2 provider. + r.Route("/oauth2", func(r chi.Router) { + r.Use( + api.oAuth2ProviderMiddleware, + // Fetch the app as system because in the /tokens route there will be no + // authenticated user. + httpmw.AsAuthzSystem(httpmw.ExtractOAuth2ProviderApp(options.Database)), + ) + r.Route("/authorize", func(r chi.Router) { + r.Use(apiKeyMiddlewareRedirect) + r.Get("/", api.getOAuth2ProviderAppAuthorize()) + }) + r.Route("/tokens", func(r chi.Router) { + r.Group(func(r chi.Router) { + r.Use(apiKeyMiddleware) + // DELETE on /tokens is not part of the OAuth2 spec. It is our own + // route used to revoke permissions from an application. It is here for + // parity with POST on /tokens. + r.Delete("/", api.deleteOAuth2ProviderAppTokens()) + }) + // The POST /tokens endpoint will be called from an unauthorized client so + // we cannot require an API key. + r.Post("/", api.postOAuth2ProviderAppToken()) + }) + }) + r.Route("/api/v2", func(r chi.Router) { api.APIHandler = r @@ -1098,6 +1126,34 @@ func New(options *Options) *API { } r.Method("GET", "/expvar", expvar.Handler()) // contains DERP metrics as well as cmdline and memstats }) + // Manage OAuth2 applications that can use Coder as an OAuth2 provider. + r.Route("/oauth2-provider", func(r chi.Router) { + r.Use( + apiKeyMiddleware, + api.oAuth2ProviderMiddleware, + ) + r.Route("/apps", func(r chi.Router) { + r.Get("/", api.oAuth2ProviderApps) + r.Post("/", api.postOAuth2ProviderApp) + + r.Route("/{app}", func(r chi.Router) { + r.Use(httpmw.ExtractOAuth2ProviderApp(options.Database)) + r.Get("/", api.oAuth2ProviderApp) + r.Put("/", api.putOAuth2ProviderApp) + r.Delete("/", api.deleteOAuth2ProviderApp) + + r.Route("/secrets", func(r chi.Router) { + r.Get("/", api.oAuth2ProviderAppSecrets) + r.Post("/", api.postOAuth2ProviderAppSecret) + + r.Route("/{secretID}", func(r chi.Router) { + r.Use(httpmw.ExtractOAuth2ProviderAppSecret(options.Database)) + r.Delete("/", api.deleteOAuth2ProviderAppSecret) + }) + }) + }) + }) + }) }) if options.SwaggerEndpoint { diff --git a/enterprise/coderd/identityprovider/authorize.go b/coderd/identityprovider/authorize.go similarity index 100% rename from enterprise/coderd/identityprovider/authorize.go rename to coderd/identityprovider/authorize.go diff --git a/enterprise/coderd/identityprovider/middleware.go b/coderd/identityprovider/middleware.go similarity index 100% rename from enterprise/coderd/identityprovider/middleware.go rename to coderd/identityprovider/middleware.go diff --git a/enterprise/coderd/identityprovider/revoke.go b/coderd/identityprovider/revoke.go similarity index 100% rename from enterprise/coderd/identityprovider/revoke.go rename to coderd/identityprovider/revoke.go diff --git a/enterprise/coderd/identityprovider/secrets.go b/coderd/identityprovider/secrets.go similarity index 100% rename from enterprise/coderd/identityprovider/secrets.go rename to coderd/identityprovider/secrets.go diff --git a/enterprise/coderd/identityprovider/tokens.go b/coderd/identityprovider/tokens.go similarity index 100% rename from enterprise/coderd/identityprovider/tokens.go rename to coderd/identityprovider/tokens.go diff --git a/enterprise/coderd/oauth2.go b/coderd/oauth2.go similarity index 94% rename from enterprise/coderd/oauth2.go rename to coderd/oauth2.go index 26b9555bf3..9e2df641bf 100644 --- a/enterprise/coderd/oauth2.go +++ b/coderd/oauth2.go @@ -13,11 +13,11 @@ import ( "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/identityprovider" "github.com/coder/coder/v2/codersdk" - "github.com/coder/coder/v2/enterprise/coderd/identityprovider" ) -func (api *API) oAuth2ProviderMiddleware(next http.Handler) http.Handler { +func (*API) oAuth2ProviderMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { if !buildinfo.IsDev() { httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{ @@ -26,17 +26,6 @@ func (api *API) oAuth2ProviderMiddleware(next http.Handler) http.Handler { return } - api.entitlementsMu.RLock() - entitled := api.entitlements.Features[codersdk.FeatureOAuth2Provider].Entitlement != codersdk.EntitlementNotEntitled - api.entitlementsMu.RUnlock() - - if !entitled { - httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{ - Message: "OAuth2 provider is an Enterprise feature. Contact sales!", - }) - return - } - next.ServeHTTP(rw, r) }) } @@ -111,7 +100,7 @@ func (api *API) oAuth2ProviderApp(rw http.ResponseWriter, r *http.Request) { func (api *API) postOAuth2ProviderApp(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() - auditor = api.AGPL.Auditor.Load() + auditor = api.Auditor.Load() aReq, commitAudit = audit.InitRequest[database.OAuth2ProviderApp](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, @@ -157,7 +146,7 @@ func (api *API) putOAuth2ProviderApp(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() app = httpmw.OAuth2ProviderApp(r) - auditor = api.AGPL.Auditor.Load() + auditor = api.Auditor.Load() aReq, commitAudit = audit.InitRequest[database.OAuth2ProviderApp](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, @@ -200,7 +189,7 @@ func (api *API) deleteOAuth2ProviderApp(rw http.ResponseWriter, r *http.Request) var ( ctx = r.Context() app = httpmw.OAuth2ProviderApp(r) - auditor = api.AGPL.Auditor.Load() + auditor = api.Auditor.Load() aReq, commitAudit = audit.InitRequest[database.OAuth2ProviderApp](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, @@ -263,7 +252,7 @@ func (api *API) postOAuth2ProviderAppSecret(rw http.ResponseWriter, r *http.Requ var ( ctx = r.Context() app = httpmw.OAuth2ProviderApp(r) - auditor = api.AGPL.Auditor.Load() + auditor = api.Auditor.Load() aReq, commitAudit = audit.InitRequest[database.OAuth2ProviderAppSecret](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, @@ -317,7 +306,7 @@ func (api *API) deleteOAuth2ProviderAppSecret(rw http.ResponseWriter, r *http.Re var ( ctx = r.Context() secret = httpmw.OAuth2ProviderAppSecret(r) - auditor = api.AGPL.Auditor.Load() + auditor = api.Auditor.Load() aReq, commitAudit = audit.InitRequest[database.OAuth2ProviderAppSecret](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, diff --git a/enterprise/coderd/oauth2_test.go b/coderd/oauth2_test.go similarity index 94% rename from enterprise/coderd/oauth2_test.go rename to coderd/oauth2_test.go index 94d221882a..f5311be173 100644 --- a/enterprise/coderd/oauth2_test.go +++ b/coderd/oauth2_test.go @@ -19,12 +19,10 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" + "github.com/coder/coder/v2/coderd/identityprovider" "github.com/coder/coder/v2/coderd/userpassword" "github.com/coder/coder/v2/coderd/util/ptr" "github.com/coder/coder/v2/codersdk" - "github.com/coder/coder/v2/enterprise/coderd/coderdenttest" - "github.com/coder/coder/v2/enterprise/coderd/identityprovider" - "github.com/coder/coder/v2/enterprise/coderd/license" "github.com/coder/coder/v2/testutil" ) @@ -34,11 +32,8 @@ func TestOAuth2ProviderApps(t *testing.T) { t.Run("Validation", func(t *testing.T) { t.Parallel() - client, _ := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + _ = coderdtest.CreateFirstUser(t, client) topCtx := testutil.Context(t, testutil.WaitLong) @@ -178,11 +173,8 @@ func TestOAuth2ProviderApps(t *testing.T) { t.Run("DeleteNonExisting", func(t *testing.T) { t.Parallel() - client, owner := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + owner := coderdtest.CreateFirstUser(t, client) another, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) ctx := testutil.Context(t, testutil.WaitLong) @@ -194,11 +186,8 @@ func TestOAuth2ProviderApps(t *testing.T) { t.Run("OK", func(t *testing.T) { t.Parallel() - client, owner := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + owner := coderdtest.CreateFirstUser(t, client) another, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) ctx := testutil.Context(t, testutil.WaitLong) @@ -269,11 +258,8 @@ func TestOAuth2ProviderApps(t *testing.T) { t.Run("ByUser", func(t *testing.T) { t.Parallel() - client, owner := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + owner := coderdtest.CreateFirstUser(t, client) another, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) ctx := testutil.Context(t, testutil.WaitLong) _ = generateApps(ctx, t, client, "by-user") @@ -288,11 +274,8 @@ func TestOAuth2ProviderApps(t *testing.T) { func TestOAuth2ProviderAppSecrets(t *testing.T) { t.Parallel() - client, _ := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + _ = coderdtest.CreateFirstUser(t, client) topCtx := testutil.Context(t, testutil.WaitLong) @@ -383,17 +366,11 @@ func TestOAuth2ProviderTokenExchange(t *testing.T) { t.Parallel() db, pubsub := dbtestutil.NewDB(t) - ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{ - Options: &coderdtest.Options{ - Database: db, - Pubsub: pubsub, - }, - LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }, + ownerClient := coderdtest.New(t, &coderdtest.Options{ + Database: db, + Pubsub: pubsub, }) + owner := coderdtest.CreateFirstUser(t, ownerClient) topCtx := testutil.Context(t, testutil.WaitLong) apps := generateApps(topCtx, t, ownerClient, "token-exchange") @@ -764,17 +741,11 @@ func TestOAuth2ProviderTokenRefresh(t *testing.T) { topCtx := testutil.Context(t, testutil.WaitLong) db, pubsub := dbtestutil.NewDB(t) - ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{ - Options: &coderdtest.Options{ - Database: db, - Pubsub: pubsub, - }, - LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }, + ownerClient := coderdtest.New(t, &coderdtest.Options{ + Database: db, + Pubsub: pubsub, }) + owner := coderdtest.CreateFirstUser(t, ownerClient) apps := generateApps(topCtx, t, ownerClient, "token-refresh") //nolint:gocritic // OAauth2 app management requires owner permission. @@ -935,11 +906,8 @@ type exchangeSetup struct { func TestOAuth2ProviderRevoke(t *testing.T) { t.Parallel() - client, owner := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureOAuth2Provider: 1, - }, - }}) + client := coderdtest.New(t, nil) + owner := coderdtest.CreateFirstUser(t, client) tests := []struct { name string @@ -1138,3 +1106,10 @@ func authorizationFlow(ctx context.Context, client *codersdk.Client, cfg *oauth2 }, ) } + +func must[T any](value T, err error) T { + if err != nil { + panic(err) + } + return value +} diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 9f387f7b0f..ee174075a7 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -53,7 +53,6 @@ const ( FeatureExternalTokenEncryption FeatureName = "external_token_encryption" FeatureWorkspaceBatchActions FeatureName = "workspace_batch_actions" FeatureAccessControl FeatureName = "access_control" - FeatureOAuth2Provider FeatureName = "oauth2_provider" FeatureControlSharedPorts FeatureName = "control_shared_ports" ) @@ -74,7 +73,6 @@ var FeatureNames = []FeatureName{ FeatureExternalTokenEncryption, FeatureWorkspaceBatchActions, FeatureAccessControl, - FeatureOAuth2Provider, FeatureControlSharedPorts, } @@ -85,8 +83,6 @@ func (n FeatureName) Humanize() string { return "Template RBAC" case FeatureSCIM: return "SCIM" - case FeatureOAuth2Provider: - return "OAuth Provider" default: return strings.Title(strings.ReplaceAll(string(n), "_", " ")) } diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 4ce4414bdc..7791959a87 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -153,16 +153,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { SessionTokenFunc: nil, // Default behavior PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc, }) - // Same as above but it redirects to the login page. - apiKeyMiddlewareRedirect := httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ - DB: options.Database, - OAuth2Configs: oauthConfigs, - RedirectToLogin: true, - DisableSessionExpiryRefresh: options.DeploymentValues.DisableSessionExpiryRefresh.Value(), - Optional: false, - SessionTokenFunc: nil, // Default behavior - PostAuthAdditionalHeadersFunc: options.PostAuthAdditionalHeadersFunc, - }) apiKeyMiddlewareOptional := httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{ DB: options.Database, OAuth2Configs: oauthConfigs, @@ -178,33 +168,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { return nil, xerrors.Errorf("failed to get deployment ID: %w", err) } - api.AGPL.RootHandler.Group(func(r chi.Router) { - // OAuth2 linking routes do not make sense under the /api/v2 path. - r.Route("/oauth2", func(r chi.Router) { - r.Use( - api.oAuth2ProviderMiddleware, - // Fetch the app as system because in the /tokens route there will be no - // authenticated user. - httpmw.AsAuthzSystem(httpmw.ExtractOAuth2ProviderApp(options.Database)), - ) - r.Route("/authorize", func(r chi.Router) { - r.Use(apiKeyMiddlewareRedirect) - r.Get("/", api.getOAuth2ProviderAppAuthorize()) - }) - r.Route("/tokens", func(r chi.Router) { - r.Group(func(r chi.Router) { - r.Use(apiKeyMiddleware) - // DELETE on /tokens is not part of the OAuth2 spec. It is our own - // route used to revoke permissions from an application. It is here for - // parity with POST on /tokens. - r.Delete("/", api.deleteOAuth2ProviderAppTokens()) - }) - // The POST /tokens endpoint will be called from an unauthorized client so we - // cannot require an API key. - r.Post("/", api.postOAuth2ProviderAppToken()) - }) - }) - }) api.AGPL.RefreshEntitlements = func(ctx context.Context) error { return api.refreshEntitlements(ctx) } @@ -365,33 +328,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { r.Get("/", api.userQuietHoursSchedule) r.Put("/", api.putUserQuietHoursSchedule) }) - r.Route("/oauth2-provider", func(r chi.Router) { - r.Use( - apiKeyMiddleware, - api.oAuth2ProviderMiddleware, - ) - r.Route("/apps", func(r chi.Router) { - r.Get("/", api.oAuth2ProviderApps) - r.Post("/", api.postOAuth2ProviderApp) - - r.Route("/{app}", func(r chi.Router) { - r.Use(httpmw.ExtractOAuth2ProviderApp(options.Database)) - r.Get("/", api.oAuth2ProviderApp) - r.Put("/", api.putOAuth2ProviderApp) - r.Delete("/", api.deleteOAuth2ProviderApp) - - r.Route("/secrets", func(r chi.Router) { - r.Get("/", api.oAuth2ProviderAppSecrets) - r.Post("/", api.postOAuth2ProviderAppSecret) - - r.Route("/{secretID}", func(r chi.Router) { - r.Use(httpmw.ExtractOAuth2ProviderAppSecret(options.Database)) - r.Delete("/", api.deleteOAuth2ProviderAppSecret) - }) - }) - }) - }) - }) r.Route("/integrations", func(r chi.Router) { r.Use( apiKeyMiddleware, @@ -596,7 +532,6 @@ func (api *API) updateEntitlements(ctx context.Context) error { codersdk.FeatureBrowserOnly: api.BrowserOnly, codersdk.FeatureSCIM: len(api.SCIMAPIKey) != 0, codersdk.FeatureMultipleExternalAuth: len(api.ExternalAuthConfigs) > 1, - codersdk.FeatureOAuth2Provider: true, codersdk.FeatureTemplateRBAC: api.RBAC, codersdk.FeatureExternalTokenEncryption: len(api.ExternalTokenEncryption) > 0, codersdk.FeatureExternalProvisionerDaemons: true, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index deb4e06363..f6dbdf131c 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2051,7 +2051,6 @@ export type FeatureName = | "external_token_encryption" | "high_availability" | "multiple_external_auth" - | "oauth2_provider" | "scim" | "template_rbac" | "user_limit" @@ -2069,7 +2068,6 @@ export const FeatureNames: FeatureName[] = [ "external_token_encryption", "high_availability", "multiple_external_auth", - "oauth2_provider", "scim", "template_rbac", "user_limit", diff --git a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPage.tsx b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPage.tsx index c45a8cd46f..455aac1a45 100644 --- a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPage.tsx +++ b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPage.tsx @@ -2,12 +2,10 @@ import type { FC } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; import { getApps } from "api/queries/oauth2"; -import { useDashboard } from "modules/dashboard/useDashboard"; import { pageTitle } from "utils/page"; import OAuth2AppsSettingsPageView from "./OAuth2AppsSettingsPageView"; const OAuth2AppsSettingsPage: FC = () => { - const { entitlements } = useDashboard(); const appsQuery = useQuery(getApps()); return ( @@ -19,9 +17,6 @@ const OAuth2AppsSettingsPage: FC = () => { apps={appsQuery.data} isLoading={appsQuery.isLoading} error={appsQuery.error} - isEntitled={ - entitlements.features.oauth2_provider.entitlement !== "not_entitled" - } /> ); diff --git a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.stories.tsx b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.stories.tsx index 71ec930b69..24006c75c7 100644 --- a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.stories.tsx +++ b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.stories.tsx @@ -23,21 +23,13 @@ export const Error: Story = { }, }; -export const Unentitled: Story = { +export const Apps: Story = { args: { isLoading: false, apps: MockOAuth2ProviderApps, }, }; -export const Entitled: Story = { - args: { - isLoading: false, - apps: MockOAuth2ProviderApps, - isEntitled: true, - }, -}; - export const Empty: Story = { args: { isLoading: false, diff --git a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.tsx b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.tsx index fee462f872..179dc6b732 100644 --- a/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.tsx +++ b/site/src/pages/DeploySettingsPage/OAuth2AppsSettingsPage/OAuth2AppsSettingsPageView.tsx @@ -14,12 +14,6 @@ import type * as TypesGen from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Avatar } from "components/Avatar/Avatar"; import { AvatarData } from "components/AvatarData/AvatarData"; -import { - Badges, - DisabledBadge, - EnterpriseBadge, - EntitledBadge, -} from "components/Badges/Badges"; import { Stack } from "components/Stack/Stack"; import { TableLoader } from "components/TableLoader/TableLoader"; import { useClickableTableRow } from "hooks/useClickableTableRow"; @@ -27,14 +21,12 @@ import { Header } from "../Header"; type OAuth2AppsSettingsProps = { apps?: TypesGen.OAuth2ProviderApp[]; - isEntitled: boolean; isLoading: boolean; error: unknown; }; const OAuth2AppsSettingsPageView: FC = ({ apps, - isEntitled, isLoading, error, }) => { @@ -50,10 +42,6 @@ const OAuth2AppsSettingsPageView: FC = ({ title="OAuth2 Applications" description="Configure applications to use Coder as an OAuth2 provider." /> - - {isEntitled ? : } - -