Skip to content

Commit

Permalink
identity/oidc: adds client_secret_post token endpoint authentication …
Browse files Browse the repository at this point in the history
…method (#16598)

* identity/oidc: adds client_secret_post token endpoint authentication method

* fix test

* adds changelog
  • Loading branch information
austingebauer committed Aug 8, 2022
1 parent 20d051c commit 0e4b329
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 15 deletions.
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

0 comments on commit 0e4b329

Please sign in to comment.