mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add endpoint and CLI for users to view their own OIDC claims (#23053)
- Adds a new API endpoint `GET /api/v2/users/oidc-claims` that returns only the **merged claims** (not the separate id_token/userinfo breakdown). Scoped exclusively to the authenticated user's own identity — no user parameter, so users cannot view each other's claims. - Adds a new CLI command:** `coder users oidc-claims` that hits the above endpoint. - The existing owner-only debug endpoint is preserved unchanged for admins who need the full claim breakdown. > 🤖 This PR was created with the help of Coder Agents, and will be reviewed by my human. 🧑💻
This commit is contained in:
+11
-10
@@ -8,16 +8,17 @@ USAGE:
|
||||
Aliases: user
|
||||
|
||||
SUBCOMMANDS:
|
||||
activate Update a user's status to 'active'. Active users can fully
|
||||
interact with the platform
|
||||
create Create a new user.
|
||||
delete Delete a user by username or user_id.
|
||||
edit-roles Edit a user's roles by username or id
|
||||
list Prints the list of users.
|
||||
show Show a single user. Use 'me' to indicate the currently
|
||||
authenticated user.
|
||||
suspend Update a user's status to 'suspended'. A suspended user cannot
|
||||
log into the platform
|
||||
activate Update a user's status to 'active'. Active users can fully
|
||||
interact with the platform
|
||||
create Create a new user.
|
||||
delete Delete a user by username or user_id.
|
||||
edit-roles Edit a user's roles by username or id
|
||||
list Prints the list of users.
|
||||
oidc-claims Display the OIDC claims for the authenticated user.
|
||||
show Show a single user. Use 'me' to indicate the currently
|
||||
authenticated user.
|
||||
suspend Update a user's status to 'suspended'. A suspended user
|
||||
cannot log into the platform
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
coder v0.0.0-devel
|
||||
|
||||
USAGE:
|
||||
coder users oidc-claims [flags]
|
||||
|
||||
Display the OIDC claims for the authenticated user.
|
||||
|
||||
- Display your OIDC claims:
|
||||
|
||||
$ coder users oidc-claims
|
||||
|
||||
- Display your OIDC claims as JSON:
|
||||
|
||||
$ coder users oidc-claims -o json
|
||||
|
||||
OPTIONS:
|
||||
-c, --column [key|value] (default: key,value)
|
||||
Columns to display in table output.
|
||||
|
||||
-o, --output table|json (default: table)
|
||||
Output format.
|
||||
|
||||
———
|
||||
Run `coder --help` for a list of global options.
|
||||
@@ -0,0 +1,79 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/cli/cliui"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/serpent"
|
||||
)
|
||||
|
||||
func (r *RootCmd) userOIDCClaims() *serpent.Command {
|
||||
formatter := cliui.NewOutputFormatter(
|
||||
cliui.ChangeFormatterData(
|
||||
cliui.TableFormat([]claimRow{}, []string{"key", "value"}),
|
||||
func(data any) (any, error) {
|
||||
resp, ok := data.(codersdk.OIDCClaimsResponse)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("expected type %T, got %T", resp, data)
|
||||
}
|
||||
rows := make([]claimRow, 0, len(resp.Claims))
|
||||
for k, v := range resp.Claims {
|
||||
rows = append(rows, claimRow{
|
||||
Key: k,
|
||||
Value: fmt.Sprintf("%v", v),
|
||||
})
|
||||
}
|
||||
return rows, nil
|
||||
},
|
||||
),
|
||||
cliui.JSONFormat(),
|
||||
)
|
||||
|
||||
cmd := &serpent.Command{
|
||||
Use: "oidc-claims",
|
||||
Short: "Display the OIDC claims for the authenticated user.",
|
||||
Long: FormatExamples(
|
||||
Example{
|
||||
Description: "Display your OIDC claims",
|
||||
Command: "coder users oidc-claims",
|
||||
},
|
||||
Example{
|
||||
Description: "Display your OIDC claims as JSON",
|
||||
Command: "coder users oidc-claims -o json",
|
||||
},
|
||||
),
|
||||
Middleware: serpent.Chain(
|
||||
serpent.RequireNArgs(0),
|
||||
),
|
||||
Handler: func(inv *serpent.Invocation) error {
|
||||
client, err := r.InitClient(inv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := client.UserOIDCClaims(inv.Context())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get oidc claims: %w", err)
|
||||
}
|
||||
|
||||
out, err := formatter.Format(inv.Context(), resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintln(inv.Stdout, out)
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
formatter.AttachOptions(&cmd.Options)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type claimRow struct {
|
||||
Key string `json:"-" table:"key,default_sort"`
|
||||
Value string `json:"-" table:"value"`
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/cli/clitest"
|
||||
"github.com/coder/coder/v2/coderd"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/coderdtest/oidctest"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestUserOIDCClaims(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fake := oidctest.NewFakeIDP(t,
|
||||
oidctest.WithServing(),
|
||||
)
|
||||
cfg := fake.OIDCConfig(t, nil, func(cfg *coderd.OIDCConfig) {
|
||||
cfg.AllowSignups = true
|
||||
})
|
||||
ownerClient := coderdtest.New(t, &coderdtest.Options{
|
||||
OIDCConfig: cfg,
|
||||
})
|
||||
|
||||
t.Run("OwnClaims", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
claims := jwt.MapClaims{
|
||||
"email": "alice@coder.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
"groups": []string{"admin", "eng"},
|
||||
}
|
||||
userClient, loginResp := fake.Login(t, ownerClient, claims)
|
||||
defer loginResp.Body.Close()
|
||||
|
||||
inv, root := clitest.New(t, "users", "oidc-claims", "-o", "json")
|
||||
clitest.SetupConfig(t, userClient, root)
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
inv.Stdout = buf
|
||||
err := inv.WithContext(testutil.Context(t, testutil.WaitMedium)).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
var resp codersdk.OIDCClaimsResponse
|
||||
err = json.Unmarshal(buf.Bytes(), &resp)
|
||||
require.NoError(t, err, "unmarshal JSON output")
|
||||
require.NotEmpty(t, resp.Claims, "claims should not be empty")
|
||||
assert.Equal(t, "alice@coder.com", resp.Claims["email"])
|
||||
})
|
||||
|
||||
t.Run("Table", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
claims := jwt.MapClaims{
|
||||
"email": "bob@coder.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
userClient, loginResp := fake.Login(t, ownerClient, claims)
|
||||
defer loginResp.Body.Close()
|
||||
|
||||
inv, root := clitest.New(t, "users", "oidc-claims")
|
||||
clitest.SetupConfig(t, userClient, root)
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
inv.Stdout = buf
|
||||
err := inv.WithContext(testutil.Context(t, testutil.WaitMedium)).Run()
|
||||
require.NoError(t, err)
|
||||
|
||||
output := buf.String()
|
||||
require.Contains(t, output, "email")
|
||||
require.Contains(t, output, "bob@coder.com")
|
||||
})
|
||||
|
||||
t.Run("NotOIDCUser", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, nil)
|
||||
_ = coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
inv, root := clitest.New(t, "users", "oidc-claims")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
err := inv.WithContext(testutil.Context(t, testutil.WaitMedium)).Run()
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "not an OIDC user")
|
||||
})
|
||||
|
||||
// Verify that two different OIDC users each only see their own
|
||||
// claims. The endpoint has no user parameter, so there is no way
|
||||
// to request another user's claims by design.
|
||||
t.Run("OnlyOwnClaims", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
aliceClaims := jwt.MapClaims{
|
||||
"email": "alice-isolation@coder.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
aliceClient, aliceLoginResp := fake.Login(t, ownerClient, aliceClaims)
|
||||
defer aliceLoginResp.Body.Close()
|
||||
|
||||
bobClaims := jwt.MapClaims{
|
||||
"email": "bob-isolation@coder.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
bobClient, bobLoginResp := fake.Login(t, ownerClient, bobClaims)
|
||||
defer bobLoginResp.Body.Close()
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
|
||||
// Alice sees her own claims.
|
||||
aliceResp, err := aliceClient.UserOIDCClaims(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "alice-isolation@coder.com", aliceResp.Claims["email"])
|
||||
|
||||
// Bob sees his own claims.
|
||||
bobResp, err := bobClient.UserOIDCClaims(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "bob-isolation@coder.com", bobResp.Claims["email"])
|
||||
})
|
||||
|
||||
t.Run("ClaimsNeverNull", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Use minimal claims — just enough for OIDC login.
|
||||
claims := jwt.MapClaims{
|
||||
"email": "minimal@coder.com",
|
||||
"email_verified": true,
|
||||
"sub": uuid.NewString(),
|
||||
}
|
||||
userClient, loginResp := fake.Login(t, ownerClient, claims)
|
||||
defer loginResp.Body.Close()
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
resp, err := userClient.UserOIDCClaims(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.Claims, "claims should never be nil, expected empty map")
|
||||
})
|
||||
}
|
||||
@@ -19,6 +19,7 @@ func (r *RootCmd) users() *serpent.Command {
|
||||
r.userSingle(),
|
||||
r.userDelete(),
|
||||
r.userEditRoles(),
|
||||
r.userOIDCClaims(),
|
||||
r.createUserStatusCommand(codersdk.UserStatusActive),
|
||||
r.createUserStatusCommand(codersdk.UserStatusSuspended),
|
||||
},
|
||||
|
||||
Generated
+35
@@ -7870,6 +7870,31 @@ const docTemplate = `{
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/oidc-claims": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get OIDC claims for the authenticated user",
|
||||
"operationId": "get-oidc-claims-for-the-authenticated-user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.OIDCClaimsResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/oidc/callback": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -16886,6 +16911,16 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.OIDCClaimsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"claims": {
|
||||
"description": "Claims are the merged claims from the OIDC provider. These\nare the union of the ID token claims and the userinfo claims,\nwhere userinfo claims take precedence on conflict.",
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.OIDCConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Generated
+31
@@ -6965,6 +6965,27 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/oidc-claims": {
|
||||
"get": {
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Users"],
|
||||
"summary": "Get OIDC claims for the authenticated user",
|
||||
"operationId": "get-oidc-claims-for-the-authenticated-user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.OIDCClaimsResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/oidc/callback": {
|
||||
"get": {
|
||||
"tags": ["Users"],
|
||||
@@ -15337,6 +15358,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.OIDCClaimsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"claims": {
|
||||
"description": "Claims are the merged claims from the OIDC provider. These\nare the union of the ID token claims and the userinfo claims,\nwhere userinfo claims take precedence on conflict.",
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.OIDCConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1496,6 +1496,7 @@ func New(options *Options) *API {
|
||||
r.Post("/", api.postUser)
|
||||
r.Get("/", api.users)
|
||||
r.Post("/logout", api.postLogout)
|
||||
r.Get("/oidc-claims", api.userOIDCClaims)
|
||||
// These routes query information about site wide roles.
|
||||
r.Route("/roles", func(r chi.Router) {
|
||||
r.Get("/", api.AssignableSiteRoles)
|
||||
|
||||
@@ -72,6 +72,64 @@ func (api *API) userDebugOIDC(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, link.Claims)
|
||||
}
|
||||
|
||||
// Returns the merged OIDC claims for the authenticated user.
|
||||
//
|
||||
// @Summary Get OIDC claims for the authenticated user
|
||||
// @ID get-oidc-claims-for-the-authenticated-user
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Users
|
||||
// @Success 200 {object} codersdk.OIDCClaimsResponse
|
||||
// @Router /users/oidc-claims [get]
|
||||
func (api *API) userOIDCClaims(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
apiKey = httpmw.APIKey(r)
|
||||
)
|
||||
|
||||
user, err := api.Database.GetUserByID(ctx, apiKey.UserID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to get user.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if user.LoginType != database.LoginTypeOIDC {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "User is not an OIDC user.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//nolint:gocritic // GetUserLinkByUserIDLoginType requires reading
|
||||
// rbac.ResourceSystem. The endpoint is scoped to the authenticated
|
||||
// user's own identity via apiKey, so this is safe.
|
||||
link, err := api.Database.GetUserLinkByUserIDLoginType(
|
||||
dbauthz.AsSystemRestricted(ctx),
|
||||
database.GetUserLinkByUserIDLoginTypeParams{
|
||||
UserID: user.ID,
|
||||
LoginType: database.LoginTypeOIDC,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to get user link.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
claims := link.Claims.MergedClaims
|
||||
if claims == nil {
|
||||
claims = map[string]interface{}{}
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.OIDCClaimsResponse{
|
||||
Claims: claims,
|
||||
})
|
||||
}
|
||||
|
||||
// Returns whether the initial user has been created or not.
|
||||
//
|
||||
// @Summary Check initial user created
|
||||
|
||||
@@ -339,6 +339,14 @@ type OIDCAuthMethod struct {
|
||||
IconURL string `json:"iconUrl"`
|
||||
}
|
||||
|
||||
// OIDCClaimsResponse represents the merged OIDC claims for a user.
|
||||
type OIDCClaimsResponse struct {
|
||||
// Claims are the merged claims from the OIDC provider. These
|
||||
// are the union of the ID token claims and the userinfo claims,
|
||||
// where userinfo claims take precedence on conflict.
|
||||
Claims map[string]interface{} `json:"claims"`
|
||||
}
|
||||
|
||||
type UserParameter struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
@@ -723,6 +731,20 @@ func (c *Client) UserRoles(ctx context.Context, user string) (UserRoles, error)
|
||||
return roles, json.NewDecoder(res.Body).Decode(&roles)
|
||||
}
|
||||
|
||||
// UserOIDCClaims returns the merged OIDC claims for the authenticated user.
|
||||
func (c *Client) UserOIDCClaims(ctx context.Context) (OIDCClaimsResponse, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/users/oidc-claims", nil)
|
||||
if err != nil {
|
||||
return OIDCClaimsResponse{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return OIDCClaimsResponse{}, ReadBodyAsError(res)
|
||||
}
|
||||
var resp OIDCClaimsResponse
|
||||
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
||||
}
|
||||
|
||||
// LoginWithPassword creates a session token authenticating with an email and password.
|
||||
// Call `SetSessionToken()` to apply the newly acquired token to the client.
|
||||
func (c *Client) LoginWithPassword(ctx context.Context, req LoginWithPasswordRequest) (LoginWithPasswordResponse, error) {
|
||||
|
||||
Generated
+14
@@ -5768,6 +5768,20 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
| `iconUrl` | string | false | | |
|
||||
| `signInText` | string | false | | |
|
||||
|
||||
## codersdk.OIDCClaimsResponse
|
||||
|
||||
```json
|
||||
{
|
||||
"claims": {}
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------|--------|----------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `claims` | object | false | | Claims are the merged claims from the OIDC provider. These are the union of the ID token claims and the userinfo claims, where userinfo claims take precedence on conflict. |
|
||||
|
||||
## codersdk.OIDCConfig
|
||||
|
||||
```json
|
||||
|
||||
Generated
+31
@@ -376,6 +376,37 @@ curl -X GET http://coder-server:8080/api/v2/users/oauth2/github/device \
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get OIDC claims for the authenticated user
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/users/oidc-claims \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /users/oidc-claims`
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"claims": {}
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
|--------|---------------------------------------------------------|-------------|----------------------------------------------------------------------|
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.OIDCClaimsResponse](schemas.md#codersdkoidcclaimsresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## OpenID Connect Callback
|
||||
|
||||
### Code samples
|
||||
|
||||
Generated
+10
-9
@@ -15,12 +15,13 @@ coder users [subcommand]
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Name | Purpose |
|
||||
|--------------------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| [<code>create</code>](./users_create.md) | Create a new user. |
|
||||
| [<code>list</code>](./users_list.md) | Prints the list of users. |
|
||||
| [<code>show</code>](./users_show.md) | Show a single user. Use 'me' to indicate the currently authenticated user. |
|
||||
| [<code>delete</code>](./users_delete.md) | Delete a user by username or user_id. |
|
||||
| [<code>edit-roles</code>](./users_edit-roles.md) | Edit a user's roles by username or id |
|
||||
| [<code>activate</code>](./users_activate.md) | Update a user's status to 'active'. Active users can fully interact with the platform |
|
||||
| [<code>suspend</code>](./users_suspend.md) | Update a user's status to 'suspended'. A suspended user cannot log into the platform |
|
||||
| Name | Purpose |
|
||||
|----------------------------------------------------|---------------------------------------------------------------------------------------|
|
||||
| [<code>create</code>](./users_create.md) | Create a new user. |
|
||||
| [<code>list</code>](./users_list.md) | Prints the list of users. |
|
||||
| [<code>show</code>](./users_show.md) | Show a single user. Use 'me' to indicate the currently authenticated user. |
|
||||
| [<code>delete</code>](./users_delete.md) | Delete a user by username or user_id. |
|
||||
| [<code>edit-roles</code>](./users_edit-roles.md) | Edit a user's roles by username or id |
|
||||
| [<code>oidc-claims</code>](./users_oidc-claims.md) | Display the OIDC claims for the authenticated user. |
|
||||
| [<code>activate</code>](./users_activate.md) | Update a user's status to 'active'. Active users can fully interact with the platform |
|
||||
| [<code>suspend</code>](./users_suspend.md) | Update a user's status to 'suspended'. A suspended user cannot log into the platform |
|
||||
|
||||
Generated
+42
@@ -0,0 +1,42 @@
|
||||
<!-- DO NOT EDIT | GENERATED CONTENT -->
|
||||
# users oidc-claims
|
||||
|
||||
Display the OIDC claims for the authenticated user.
|
||||
|
||||
## Usage
|
||||
|
||||
```console
|
||||
coder users oidc-claims [flags]
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
```console
|
||||
- Display your OIDC claims:
|
||||
|
||||
$ coder users oidc-claims
|
||||
|
||||
- Display your OIDC claims as JSON:
|
||||
|
||||
$ coder users oidc-claims -o json
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### -c, --column
|
||||
|
||||
| | |
|
||||
|---------|---------------------------|
|
||||
| Type | <code>[key\|value]</code> |
|
||||
| Default | <code>key,value</code> |
|
||||
|
||||
Columns to display in table output.
|
||||
|
||||
### -o, --output
|
||||
|
||||
| | |
|
||||
|---------|--------------------------|
|
||||
| Type | <code>table\|json</code> |
|
||||
| Default | <code>table</code> |
|
||||
|
||||
Output format.
|
||||
Generated
+14
@@ -4339,6 +4339,20 @@ export interface OIDCAuthMethod extends AuthMethod {
|
||||
readonly iconUrl: string;
|
||||
}
|
||||
|
||||
// From codersdk/users.go
|
||||
/**
|
||||
* OIDCClaimsResponse represents the merged OIDC claims for a user.
|
||||
*/
|
||||
export interface OIDCClaimsResponse {
|
||||
/**
|
||||
* Claims are the merged claims from the OIDC provider. These
|
||||
* are the union of the ID token claims and the userinfo claims,
|
||||
* where userinfo claims take precedence on conflict.
|
||||
*/
|
||||
// empty interface{} type, falling back to unknown
|
||||
readonly claims: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// From codersdk/deployment.go
|
||||
export interface OIDCConfig {
|
||||
readonly allow_signups: boolean;
|
||||
|
||||
Reference in New Issue
Block a user