Skip to content
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

identity/oidc: adds client_secret_post token endpoint authentication method #16598

Merged
merged 4 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions changelog/16598.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
identity/oidc: Adds the `client_secret_post` token endpoint authentication method.
```
16 changes: 11 additions & 5 deletions vault/identity_store_oidc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ func oidcProviderPaths(i *IdentityStore) []*framework.Path {
Description: "The code verifier associated with the authorization code.",
},
// For confidential clients, the client_id and client_secret are provided to
// the token endpoint via the 'client_secret_basic' authentication method, which
// uses the HTTP Basic authentication scheme. See the OIDC spec for details at:
// the token endpoint via the 'client_secret_basic' or 'client_secret_post'
// authentication methods. See the OIDC spec for details at:
// https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication

// For public clients, the client_id is required and a client_secret does
Expand All @@ -522,6 +522,10 @@ func oidcProviderPaths(i *IdentityStore) []*framework.Path {
Type: framework.TypeString,
Description: "The ID of the requesting client.",
},
"client_secret": {
Type: framework.TypeString,
Description: "The secret of the requesting client.",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Expand Down Expand Up @@ -1483,6 +1487,7 @@ func (i *IdentityStore) pathOIDCProviderDiscovery(ctx context.Context, req *logi
// PKCE is required for auth method "none"
"none",
"client_secret_basic",
"client_secret_post",
},
}

Expand Down Expand Up @@ -1856,13 +1861,15 @@ func (i *IdentityStore) pathOIDCToken(ctx context.Context, req *logical.Request,
return tokenResponse(nil, ErrTokenInvalidRequest, "provider not found")
}

// Get the client ID
// client_secret_basic - Check for client credentials in the Authorization header
clientID, clientSecret, okBasicAuth := basicAuth(req)
if !okBasicAuth {
// client_secret_post - Check for client credentials in the request body
clientID = d.Get("client_id").(string)
if clientID == "" {
return tokenResponse(nil, ErrTokenInvalidRequest, "client_id parameter is required")
}
clientSecret = d.Get("client_secret").(string)
}
client, err := i.clientByID(ctx, req.Storage, clientID)
if err != nil {
Expand All @@ -1873,8 +1880,7 @@ func (i *IdentityStore) pathOIDCToken(ctx context.Context, req *logical.Request,
return tokenResponse(nil, ErrTokenInvalidClient, "client failed to authenticate")
}

// Authenticate the client using the client_secret_basic authentication method if it's a
// confidential client. The authentication method uses the HTTP Basic authentication scheme.
// Authenticate the client if it's a confidential client type.
// Details at https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
if client.Type == confidential &&
subtle.ConstantTimeCompare([]byte(client.ClientSecret), []byte(clientSecret)) == 0 {
Expand Down
20 changes: 18 additions & 2 deletions vault/identity_store_oidc_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,22 @@ func TestOIDC_Path_OIDC_Token(t *testing.T) {
tokenReq: testTokenReq(s, "", clientID, clientSecret),
},
},
{
name: "valid token request with client_secret_post client authentication method",
args: args{
clientReq: testClientReq(s),
providerReq: testProviderReq(s, clientID),
assignmentReq: testAssignmentReq(s, entityID, groupID),
authorizeReq: testAuthorizeReq(s, clientID),
tokenReq: func() *logical.Request {
req := testTokenReq(s, "", clientID, clientSecret)
req.Headers = nil
req.Data["client_id"] = clientID
req.Data["client_secret"] = clientSecret
return req
}(),
},
},
{
name: "valid token request",
args: args{
Expand Down Expand Up @@ -3613,7 +3629,7 @@ func TestOIDC_Path_OpenIDProviderConfig(t *testing.T) {
TokenEndpoint: basePath + "/token",
UserinfoEndpoint: basePath + "/userinfo",
GrantTypes: []string{"authorization_code"},
AuthMethods: []string{"none", "client_secret_basic"},
AuthMethods: []string{"none", "client_secret_basic", "client_secret_post"},
RequestParameter: false,
RequestURIParameter: false,
}
Expand Down Expand Up @@ -3668,7 +3684,7 @@ func TestOIDC_Path_OpenIDProviderConfig(t *testing.T) {
TokenEndpoint: basePath + "/token",
UserinfoEndpoint: basePath + "/userinfo",
GrantTypes: []string{"authorization_code"},
AuthMethods: []string{"none", "client_secret_basic"},
AuthMethods: []string{"none", "client_secret_basic", "client_secret_post"},
RequestParameter: false,
RequestURIParameter: false,
}
Expand Down
18 changes: 12 additions & 6 deletions website/content/api-docs/secret/identity/oidc-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ This endpoint creates or updates a client.
- `confidential`
- Capable of maintaining the confidentiality of its credentials
- Has a client secret
- Uses the `client_secret_basic` [client authentication method](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)
- Uses the `client_secret_basic` or `client_secret_post` [client authentication method](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)
- May use Proof Key for Code Exchange ([PKCE](https://datatracker.ietf.org/doc/html/rfc7636))
for the authorization code flow
- `public`
Expand Down Expand Up @@ -602,6 +602,7 @@ $ curl \
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
"none"
]}
```
Expand Down Expand Up @@ -737,19 +738,24 @@ for an OIDC provider.
authorization request was sent. This must match the `redirect_uri` used when the
original authorization code was generated.

- `client_id` `(string: <required>)` - The ID of the requesting client. This parameter
is only required for `public` clients which do not have a client secret. `confidential`
clients should not use this parameter.
- `client_id` `(string: <optional>)` - The ID of the requesting client. This parameter
is required for `public` clients which do not have a client secret or `confidential`
clients using the `client_secret_post` client authentication method.

- `client_secret` `(string: <optional>)` - The secret of the requesting client. This
parameter is required for `confidential` clients using the `client_secret_post` client
authentication method.

- `code_verifier` `(string: <optional>)` - The code verifier associated with the given
`code`. Required for authorization codes that were granted using [PKCE](https://datatracker.ietf.org/doc/html/rfc7636).
Required for `public` clients.

### Headers

- `Authorization: Basic` `(string: <required>)` - An HTTP Basic authentication scheme header
- `Authorization: Basic` `(string: <optional>)` - An HTTP Basic authentication scheme header
including the `client_id` and `client_secret` as described in the [client_secret_basic](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)
authentication method. This header is only required for `confidential` clients.
authentication method. This header is only required for `confidential` clients using
the `client_secret_basic` client authentication method.

### Sample Request

Expand Down
2 changes: 1 addition & 1 deletion website/content/docs/concepts/oidc-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Confidential clients may use Proof Key for Code Exchange ([PKCE](https://datatra
during the authorization code flow.

Confidential clients must authenticate to the token endpoint using the
`client_secret_basic` [client authentication method](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication).
`client_secret_basic` or `client_secret_post` [client authentication method](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication).

##### Public

Expand Down
3 changes: 2 additions & 1 deletion website/content/docs/secrets/identity/oidc-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ Any Vault auth method may be used within the OIDC flow. For simplicity, enable t
],
"token_endpoint_auth_methods_supported": [
"none",
"client_secret_basic"
"client_secret_basic",
"client_secret_post"
]
}
```
Expand Down