Skip to content

Commit add4d6f

Browse files
committed
update FE to add external settings page
1 parent a84ed83 commit add4d6f

File tree

12 files changed

+281
-101
lines changed

12 files changed

+281
-101
lines changed

coderd/apidoc/docs.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/db2sdk/db2sdk.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,28 @@ import (
1616
"github.com/coder/coder/v2/provisionersdk/proto"
1717
)
1818

19-
func ExternalAuths(auths []database.ExternalAuthLink) []codersdk.ExternalAuthLink {
19+
type ExternalAuthMeta struct {
20+
Authenticated bool
21+
ValidateError string
22+
}
23+
24+
func ExternalAuths(auths []database.ExternalAuthLink, meta map[string]ExternalAuthMeta) []codersdk.ExternalAuthLink {
2025
out := make([]codersdk.ExternalAuthLink, 0, len(auths))
2126
for _, auth := range auths {
22-
out = append(out, ExternalAuth(auth))
27+
out = append(out, ExternalAuth(auth, meta[auth.ProviderID]))
2328
}
2429
return out
2530
}
2631

27-
func ExternalAuth(auth database.ExternalAuthLink) codersdk.ExternalAuthLink {
32+
func ExternalAuth(auth database.ExternalAuthLink, meta ExternalAuthMeta) codersdk.ExternalAuthLink {
2833
return codersdk.ExternalAuthLink{
2934
ProviderID: auth.ProviderID,
3035
CreatedAt: auth.CreatedAt,
3136
UpdatedAt: auth.UpdatedAt,
3237
HasRefreshToken: auth.OAuthRefreshToken != "",
3338
Expires: auth.OAuthExpiry,
39+
Authenticated: meta.Authenticated,
40+
ValidateError: meta.ValidateError,
3441
}
3542
}
3643

coderd/externalauth.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,44 @@ func (api *API) listUserExternalAuths(rw http.ResponseWriter, r *http.Request) {
337337
return
338338
}
339339

340+
// This process of authenticating each external link increases the
341+
// response time. However, it is necessary to more correctly debug
342+
// authentication issues.
343+
// We can do this in parallel if we want to speed it up.
344+
configs := make(map[string]*externalauth.Config)
345+
for _, cfg := range api.ExternalAuthConfigs {
346+
configs[cfg.ID] = cfg
347+
}
348+
// Check if the links are authenticated.
349+
linkMeta := make(map[string]db2sdk.ExternalAuthMeta)
350+
for i, link := range links {
351+
if link.OAuthAccessToken != "" {
352+
cfg, ok := configs[link.ProviderID]
353+
if ok {
354+
newLink, valid, err := cfg.RefreshToken(ctx, api.Database, link)
355+
meta := db2sdk.ExternalAuthMeta{
356+
Authenticated: valid,
357+
}
358+
if err != nil {
359+
meta.ValidateError = err.Error()
360+
}
361+
// Update the link if it was potentially refreshed.
362+
if err == nil && valid {
363+
links[i] = newLink
364+
}
365+
break
366+
}
367+
}
368+
}
369+
340370
// Note: It would be really nice if we could cfg.Validate() the links and
341371
// return their authenticated status. To do this, we would also have to
342372
// refresh expired tokens too. For now, I do not want to cause the excess
343373
// traffic on this request, so the user will have to do this with a separate
344374
// call.
345375
httpapi.Write(ctx, rw, http.StatusOK, codersdk.ListUserExternalAuthResponse{
346376
Providers: ExternalAuthConfigs(api.ExternalAuthConfigs),
347-
Links: db2sdk.ExternalAuths(links),
377+
Links: db2sdk.ExternalAuths(links, linkMeta),
348378
})
349379
}
350380

codersdk/externalauth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ type ExternalAuthLink struct {
7676
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
7777
HasRefreshToken bool `json:"has_refresh_token"`
7878
Expires time.Time `json:"expires" format:"date-time"`
79+
Authenticated bool `json:"authenticated"`
80+
ValidateError string `json:"validate_error"`
7981
}
8082

8183
// ExternalAuthLinkProvider are the static details of a provider.

docs/api/git.md

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/api/schemas.md

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/api/queries/externalauth.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ export const listUserExternalAuths = () => {
1111
};
1212
};
1313

14+
const getUserExternalAuthKey = (providerID: string) => [
15+
providerID,
16+
"get",
17+
"external-auth",
18+
];
19+
20+
export const userExternalAuth = (providerID: string) => {
21+
return {
22+
queryKey: getUserExternalAuthKey(providerID),
23+
queryFn: () => API.getExternalAuthProvider(providerID),
24+
};
25+
};
26+
1427
export const validateExternalAuth = (_: QueryClient) => {
1528
return {
1629
mutationFn: API.getExternalAuthProvider,

site/src/api/typesGenerated.ts

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/pages/CreateWorkspacePage/ExternalAuth.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface ExternalAuthProps {
1515
externalAuthPollingState: ExternalAuthPollingState;
1616
startPollingExternalAuth: () => void;
1717
error?: string;
18+
message?: string;
1819
}
1920

2021
export const ExternalAuth: FC<ExternalAuthProps> = (props) => {
@@ -26,8 +27,14 @@ export const ExternalAuth: FC<ExternalAuthProps> = (props) => {
2627
externalAuthPollingState,
2728
startPollingExternalAuth,
2829
error,
30+
message,
2931
} = props;
3032

33+
const messageContent =
34+
message ??
35+
(authenticated
36+
? `Authenticated with ${displayName}`
37+
: `Login with ${displayName}`);
3138
return (
3239
<Tooltip
3340
title={authenticated && `${displayName} has already been connected.`}
@@ -40,12 +47,14 @@ export const ExternalAuth: FC<ExternalAuthProps> = (props) => {
4047
variant="contained"
4148
size="large"
4249
startIcon={
43-
<img
44-
src={displayIcon}
45-
alt={`${displayName} Icon`}
46-
width={16}
47-
height={16}
48-
/>
50+
displayIcon && (
51+
<img
52+
src={displayIcon}
53+
alt={`${displayName} Icon`}
54+
width={16}
55+
height={16}
56+
/>
57+
)
4958
}
5059
disabled={authenticated}
5160
css={{ height: 52 }}
@@ -61,9 +70,7 @@ export const ExternalAuth: FC<ExternalAuthProps> = (props) => {
6170
startPollingExternalAuth();
6271
}}
6372
>
64-
{authenticated
65-
? `Authenticated with ${displayName}`
66-
: `Login with ${displayName}`}
73+
{messageContent}
6774
</LoadingButton>
6875

6976
{externalAuthPollingState === "abandoned" && (

0 commit comments

Comments
 (0)