Skip to content

feat: allow external services to be authable #9996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Change the name of external auth
  • Loading branch information
kylecarbs committed Oct 2, 2023
commit e6c047c043040c1d7bd437212aacc5bad1cfed6e
84 changes: 44 additions & 40 deletions docs/admin/git-providers.md → docs/admin/external-auth.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
# Git Providers
# External Authentication

Coder integrates with git providers to automate away the need for developers to
authenticate with repositories within their workspace.
Coder integrates with Git and OpenID Connect to automate away the need for
developers to authenticate with external services within their workspace.

## How it works
## Git Providers

When developers use `git` inside their workspace, they are prompted to
authenticate. After that, Coder will store and refresh tokens for future
operations.

<video autoplay playsinline loop>
<source src="https://github.com/coder/coder/blob/main/site/static/gitauth.mp4?raw=true" type="video/mp4">
<source src="https://github.com/coder/coder/blob/main/site/static/external-auth.mp4?raw=true" type="video/mp4">
Your browser does not support the video tag.
</video>

## Configuration

To add a git provider, you'll need to create an OAuth application. The following
providers are supported:
To add an external authentication provider, you'll need to create an OAuth
application. The following providers are supported:

- [GitHub](#github-app)
- [GitHub](#github)
- [GitLab](https://docs.gitlab.com/ee/integration/oauth_provider.html)
- [BitBucket](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/)
- [Azure DevOps](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops)

Example callback URL:
`https://coder.example.com/gitauth/primary-github/callback`. Use an arbitrary ID
for your provider (e.g. `primary-github`).
`https://coder.example.com/external-auth/primary-github/callback`. Use an
arbitrary ID for your provider (e.g. `primary-github`).

Set the following environment variables to
[configure the Coder server](./configure.md):

```env
CODER_GITAUTH_0_ID="primary-github"
CODER_GITAUTH_0_TYPE=github|gitlab|azure-devops|bitbucket
CODER_GITAUTH_0_CLIENT_ID=xxxxxx
CODER_GITAUTH_0_CLIENT_SECRET=xxxxxxx
CODER_EXTERNAL_AUTH_0_ID="primary-github"
CODER_EXTERNAL_AUTH_0_TYPE=github|gitlab|azure-devops|bitbucket|oidc
CODER_EXTERNAL_AUTH_0_CLIENT_ID=xxxxxx
CODER_EXTERNAL_AUTH_0_CLIENT_SECRET=xxxxxxx

# Optionally, configure a custom display name and icon
CODER_EXTERNAL_AUTH_0_DISPLAY_NAME="Google Calendar"
CODER_EXTERNAL_AUTH_0_DISPLAY_ICON="https://mycustomicon.com/google.svg"
```

### GitHub
Expand Down Expand Up @@ -69,23 +73,23 @@ CODER_GITAUTH_0_CLIENT_SECRET=xxxxxxx
GitHub Enterprise requires the following authentication and token URLs:

```env
CODER_GITAUTH_0_VALIDATE_URL="https://github.example.com/login/oauth/access_token/info"
CODER_GITAUTH_0_AUTH_URL="https://github.example.com/login/oauth/authorize"
CODER_GITAUTH_0_TOKEN_URL="https://github.example.com/login/oauth/access_token"
CODER_EXTERNAL_AUTH_0_VALIDATE_URL="https://github.example.com/login/oauth/access_token/info"
CODER_EXTERNAL_AUTH_0_AUTH_URL="https://github.example.com/login/oauth/authorize"
CODER_EXTERNAL_AUTH_0_TOKEN_URL="https://github.example.com/login/oauth/access_token"
```

### Azure DevOps

Azure DevOps requires the following environment variables:

```env
CODER_GITAUTH_0_ID="primary-azure-devops"
CODER_GITAUTH_0_TYPE=azure-devops
CODER_GITAUTH_0_CLIENT_ID=xxxxxx
CODER_EXTERNAL_AUTH_0_ID="primary-azure-devops"
CODER_EXTERNAL_AUTH_0_TYPE=azure-devops
CODER_EXTERNAL_AUTH_0_CLIENT_ID=xxxxxx
# Ensure this value is your "Client Secret", not "App Secret"
CODER_GITAUTH_0_CLIENT_SECRET=xxxxxxx
CODER_GITAUTH_0_AUTH_URL="https://app.vssps.visualstudio.com/oauth2/authorize"
CODER_GITAUTH_0_TOKEN_URL="https://app.vssps.visualstudio.com/oauth2/token"
CODER_EXTERNAL_AUTH_0_CLIENT_SECRET=xxxxxxx
CODER_EXTERNAL_AUTH_0_AUTH_URL="https://app.vssps.visualstudio.com/oauth2/authorize"
CODER_EXTERNAL_AUTH_0_TOKEN_URL="https://app.vssps.visualstudio.com/oauth2/token"
```

### Self-managed git providers
Expand All @@ -94,17 +98,17 @@ Custom authentication and token URLs should be used for self-managed Git
provider deployments.

```env
CODER_GITAUTH_0_AUTH_URL="https://github.example.com/oauth/authorize"
CODER_GITAUTH_0_TOKEN_URL="https://github.example.com/oauth/token"
CODER_GITAUTH_0_VALIDATE_URL="https://your-domain.com/oauth/token/info"
CODER_EXTERNAL_AUTH_0_AUTH_URL="https://github.example.com/oauth/authorize"
CODER_EXTERNAL_AUTH_0_TOKEN_URL="https://github.example.com/oauth/token"
CODER_EXTERNAL_AUTH_0_VALIDATE_URL="https://your-domain.com/oauth/token/info"
```

### Custom scopes

Optionally, you can request custom scopes:

```env
CODER_GITAUTH_0_SCOPES="repo:read repo:write write:gpg_key"
CODER_EXTERNAL_AUTH_0_SCOPES="repo:read repo:write write:gpg_key"
```

### Multiple git providers (enterprise)
Expand All @@ -116,21 +120,21 @@ limit auth scope. Here's a sample config:

```env
# Provider 1) github.com
CODER_GITAUTH_0_ID=primary-github
CODER_GITAUTH_0_TYPE=github
CODER_GITAUTH_0_CLIENT_ID=xxxxxx
CODER_GITAUTH_0_CLIENT_SECRET=xxxxxxx
CODER_GITAUTH_0_REGEX=github.com/orgname
CODER_EXTERNAL_AUTH_0_ID=primary-github
CODER_EXTERNAL_AUTH_0_TYPE=github
CODER_EXTERNAL_AUTH_0_CLIENT_ID=xxxxxx
CODER_EXTERNAL_AUTH_0_CLIENT_SECRET=xxxxxxx
CODER_EXTERNAL_AUTH_0_REGEX=github.com/orgname

# Provider 2) github.example.com
CODER_GITAUTH_1_ID=secondary-github
CODER_GITAUTH_1_TYPE=github
CODER_GITAUTH_1_CLIENT_ID=xxxxxx
CODER_GITAUTH_1_CLIENT_SECRET=xxxxxxx
CODER_GITAUTH_1_REGEX=github.example.com
CODER_GITAUTH_1_AUTH_URL="https://github.example.com/login/oauth/authorize"
CODER_GITAUTH_1_TOKEN_URL="https://github.example.com/login/oauth/access_token"
CODER_GITAUTH_1_VALIDATE_URL="https://github.example.com/login/oauth/access_token/info"
CODER_EXTERNAL_AUTH_1_ID=secondary-github
CODER_EXTERNAL_AUTH_1_TYPE=github
CODER_EXTERNAL_AUTH_1_CLIENT_ID=xxxxxx
CODER_EXTERNAL_AUTH_1_CLIENT_SECRET=xxxxxxx
CODER_EXTERNAL_AUTH_1_REGEX=github.example.com
CODER_EXTERNAL_AUTH_1_AUTH_URL="https://github.example.com/login/oauth/authorize"
CODER_EXTERNAL_AUTH_1_TOKEN_URL="https://github.example.com/login/oauth/access_token"
CODER_EXTERNAL_AUTH_1_VALIDATE_URL="https://github.example.com/login/oauth/access_token/info"
```

To support regex matching for paths (e.g. github.com/orgname), you'll need to
Expand Down
6 changes: 3 additions & 3 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,9 @@
"icon_path": "./images/icons/toggle_on.svg"
},
{
"title": "Git Providers",
"description": "Learn how connect Coder with external git providers",
"path": "./admin/git-providers.md",
"title": "External Auth",
"description": "Learn how connect Coder with external auth providers",
"path": "./admin/external-auth.md",
"icon_path": "./images/icons/git.svg"
},
{
Expand Down
9 changes: 6 additions & 3 deletions site/src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ const UserAuthSettingsPage = lazy(
"./pages/DeploySettingsPage/UserAuthSettingsPage/UserAuthSettingsPage"
),
);
const GitAuthSettingsPage = lazy(
const ExternalAuthSettingsPage = lazy(
() =>
import(
"./pages/DeploySettingsPage/GitAuthSettingsPage/GitAuthSettingsPage"
"./pages/DeploySettingsPage/ExternalAuthSettingsPage/ExternalAuthSettingsPage"
),
);
const NetworkSettingsPage = lazy(
Expand Down Expand Up @@ -292,7 +292,10 @@ export const AppRouter: FC = () => {
<Route path="appearance" element={<AppearanceSettingsPage />} />
<Route path="network" element={<NetworkSettingsPage />} />
<Route path="userauth" element={<UserAuthSettingsPage />} />
<Route path="gitauth" element={<GitAuthSettingsPage />} />
<Route
path="external-auth"
element={<ExternalAuthSettingsPage />}
/>
<Route
path="workspace-proxies"
element={<WorkspaceProxyPage />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ import { useDeploySettings } from "components/DeploySettingsLayout/DeploySetting
import { FC } from "react";
import { Helmet } from "react-helmet-async";
import { pageTitle } from "utils/page";
import { GitAuthSettingsPageView } from "./GitAuthSettingsPageView";
import { ExternalAuthSettingsPageView } from "./ExternalAuthSettingsPageView";

const GitAuthSettingsPage: FC = () => {
const ExternalAuthSettingsPage: FC = () => {
const { deploymentValues: deploymentValues } = useDeploySettings();

return (
<>
<Helmet>
<title>{pageTitle("Git Authentication Settings")}</title>
<title>{pageTitle("External Authentication Settings")}</title>
</Helmet>

<GitAuthSettingsPageView config={deploymentValues.config} />
<ExternalAuthSettingsPageView config={deploymentValues.config} />
</>
);
};

export default GitAuthSettingsPage;
export default ExternalAuthSettingsPage;
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { GitAuthSettingsPageView } from "./GitAuthSettingsPageView";
import { ExternalAuthSettingsPageView } from "./ExternalAuthSettingsPageView";
import type { Meta, StoryObj } from "@storybook/react";

const meta: Meta<typeof GitAuthSettingsPageView> = {
title: "pages/GitAuthSettingsPageView",
component: GitAuthSettingsPageView,
const meta: Meta<typeof ExternalAuthSettingsPageView> = {
title: "pages/ExternalAuthSettingsPageView",
component: ExternalAuthSettingsPageView,
args: {
config: {
git_auth: [
external_auth: [
{
id: "0000-1111",
type: "GitHub",
Expand All @@ -30,6 +30,6 @@ const meta: Meta<typeof GitAuthSettingsPageView> = {
};

export default meta;
type Story = StoryObj<typeof GitAuthSettingsPageView>;
type Story = StoryObj<typeof ExternalAuthSettingsPageView>;

export const Page: Story = {};
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,35 @@ import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import { DeploymentValues, GitAuthConfig } from "api/typesGenerated";
import { DeploymentValues, ExternalAuthConfig } from "api/typesGenerated";
import { Alert } from "components/Alert/Alert";
import { EnterpriseBadge } from "components/DeploySettingsLayout/Badges";
import { Header } from "components/DeploySettingsLayout/Header";
import { docs } from "utils/docs";

export type GitAuthSettingsPageViewProps = {
export type ExternalAuthSettingsPageViewProps = {
config: DeploymentValues;
};

export const GitAuthSettingsPageView = ({
export const ExternalAuthSettingsPageView = ({
config,
}: GitAuthSettingsPageViewProps): JSX.Element => {
}: ExternalAuthSettingsPageViewProps): JSX.Element => {
const styles = useStyles();

return (
<>
<Header
title="Git Authentication"
description="Coder integrates with GitHub, GitLab, BitBucket, and Azure Repos to authenticate developers with your Git provider."
docsHref={docs("/admin/git-providers")}
title="External Authentication"
description="Coder integrates with GitHub, GitLab, BitBucket, Azure Repos, and OpenID Connect to authenticate developers with external services."
docsHref={docs("/admin/external-auth")}
/>

<video
autoPlay
muted
loop
playsInline
src="/gitauth.mp4"
src="/external-auth.mp4"
style={{
maxWidth: "100%",
borderRadius: 4,
Expand All @@ -42,7 +42,8 @@ export const GitAuthSettingsPageView = ({

<div className={styles.description}>
<Alert severity="info" actions={<EnterpriseBadge key="enterprise" />}>
Integrating with multiple Git providers is an Enterprise feature.
Integrating with multiple External authentication providers is an
Enterprise feature.
</Alert>
</div>

Expand All @@ -56,7 +57,8 @@ export const GitAuthSettingsPageView = ({
</TableRow>
</TableHead>
<TableBody>
{((config.git_auth === null || config.git_auth?.length === 0) && (
{((config.external_auth === null ||
config.external_auth?.length === 0) && (
<TableRow>
<TableCell colSpan={999}>
<div className={styles.empty}>
Expand All @@ -65,7 +67,7 @@ export const GitAuthSettingsPageView = ({
</TableCell>
</TableRow>
)) ||
config.git_auth?.map((git: GitAuthConfig) => {
config.external_auth?.map((git: ExternalAuthConfig) => {
const name = git.id || git.type;
return (
<TableRow key={name}>
Expand Down
4 changes: 3 additions & 1 deletion site/src/pages/ExternalAuthPage/ExternalAuthPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ const ExternalAuthPageView: FC<ExternalAuthPageViewProps> = ({

return (
<SignInLayout>
<Welcome message={`You've authenticated with ${externalAuth.display_name}!`} />
<Welcome
message={`You've authenticated with ${externalAuth.display_name}!`}
/>
<p className={styles.text}>
{externalAuth.user?.login && `Hey @${externalAuth.user?.login}! 👋 `}
{(!externalAuth.app_installable ||
Expand Down
File renamed without changes.