feat: add user/settings page for managing external auth (#10945)

Also add support for unlinking on the coder side to allow reflow.
This commit is contained in:
Steven Masley
2023-12-06 08:41:45 -06:00
committed by GitHub
parent f6891bc465
commit b376b2cd13
18 changed files with 577 additions and 23 deletions
+6
View File
@@ -8907,6 +8907,9 @@ const docTemplate = `{
"codersdk.ExternalAuthLink": {
"type": "object",
"properties": {
"authenticated": {
"type": "boolean"
},
"created_at": {
"type": "string",
"format": "date-time"
@@ -8924,6 +8927,9 @@ const docTemplate = `{
"updated_at": {
"type": "string",
"format": "date-time"
},
"validate_error": {
"type": "string"
}
}
},
+6
View File
@@ -7993,6 +7993,9 @@
"codersdk.ExternalAuthLink": {
"type": "object",
"properties": {
"authenticated": {
"type": "boolean"
},
"created_at": {
"type": "string",
"format": "date-time"
@@ -8010,6 +8013,9 @@
"updated_at": {
"type": "string",
"format": "date-time"
},
"validate_error": {
"type": "string"
}
}
},
+10 -3
View File
@@ -16,21 +16,28 @@ import (
"github.com/coder/coder/v2/provisionersdk/proto"
)
func ExternalAuths(auths []database.ExternalAuthLink) []codersdk.ExternalAuthLink {
type ExternalAuthMeta struct {
Authenticated bool
ValidateError string
}
func ExternalAuths(auths []database.ExternalAuthLink, meta map[string]ExternalAuthMeta) []codersdk.ExternalAuthLink {
out := make([]codersdk.ExternalAuthLink, 0, len(auths))
for _, auth := range auths {
out = append(out, ExternalAuth(auth))
out = append(out, ExternalAuth(auth, meta[auth.ProviderID]))
}
return out
}
func ExternalAuth(auth database.ExternalAuthLink) codersdk.ExternalAuthLink {
func ExternalAuth(auth database.ExternalAuthLink, meta ExternalAuthMeta) codersdk.ExternalAuthLink {
return codersdk.ExternalAuthLink{
ProviderID: auth.ProviderID,
CreatedAt: auth.CreatedAt,
UpdatedAt: auth.UpdatedAt,
HasRefreshToken: auth.OAuthRefreshToken != "",
Expires: auth.OAuthExpiry,
Authenticated: meta.Authenticated,
ValidateError: meta.ValidateError,
}
}
+31 -1
View File
@@ -337,6 +337,36 @@ func (api *API) listUserExternalAuths(rw http.ResponseWriter, r *http.Request) {
return
}
// This process of authenticating each external link increases the
// response time. However, it is necessary to more correctly debug
// authentication issues.
// We can do this in parallel if we want to speed it up.
configs := make(map[string]*externalauth.Config)
for _, cfg := range api.ExternalAuthConfigs {
configs[cfg.ID] = cfg
}
// Check if the links are authenticated.
linkMeta := make(map[string]db2sdk.ExternalAuthMeta)
for i, link := range links {
if link.OAuthAccessToken != "" {
cfg, ok := configs[link.ProviderID]
if ok {
newLink, valid, err := cfg.RefreshToken(ctx, api.Database, link)
meta := db2sdk.ExternalAuthMeta{
Authenticated: valid,
}
if err != nil {
meta.ValidateError = err.Error()
}
// Update the link if it was potentially refreshed.
if err == nil && valid {
links[i] = newLink
}
break
}
}
}
// Note: It would be really nice if we could cfg.Validate() the links and
// return their authenticated status. To do this, we would also have to
// refresh expired tokens too. For now, I do not want to cause the excess
@@ -344,7 +374,7 @@ func (api *API) listUserExternalAuths(rw http.ResponseWriter, r *http.Request) {
// call.
httpapi.Write(ctx, rw, http.StatusOK, codersdk.ListUserExternalAuthResponse{
Providers: ExternalAuthConfigs(api.ExternalAuthConfigs),
Links: db2sdk.ExternalAuths(links),
Links: db2sdk.ExternalAuths(links, linkMeta),
})
}