diff --git a/.changeset/dull-dolphins-return.md b/.changeset/dull-dolphins-return.md new file mode 100644 index 000000000..fef769a2d --- /dev/null +++ b/.changeset/dull-dolphins-return.md @@ -0,0 +1,13 @@ +--- +"@logto/core": patch +--- + +remove `client_id` from OIDC SSO connector's token request body for better compatibility + +This updates addresses an issue with client authentication methods in the token request process. Previously, the `client_id` was included in the request body while also using the authentication header for client credentials authentication. + +This dual method of client authentication can lead to errors with certain OIDC providers, such as Okta, which only support one authentication method at a time. + +### Key changes + +Removal of `client_id` from request body: The `client_id` parameter has been removed from the token request body. According to the [OAuth 2.0 specification](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3), `client_id` in the body is required only for public clients. diff --git a/packages/core/src/saml-application/SamlApplication/index.test.ts b/packages/core/src/saml-application/SamlApplication/index.test.ts index ccc0c14ac..cedbb0199 100644 --- a/packages/core/src/saml-application/SamlApplication/index.test.ts +++ b/packages/core/src/saml-application/SamlApplication/index.test.ts @@ -121,7 +121,7 @@ describe('SamlApplication', () => { nock(mockEndpoint) .post( '/token', - `grant_type=authorization_code&code=${mockCode}&client_id=${mockSamlApplicationId}&redirect_uri=${encodeURIComponent( + `grant_type=authorization_code&code=${mockCode}&redirect_uri=${encodeURIComponent( samlApp.config.redirectUri )}` ) diff --git a/packages/core/src/sso/OidcConnector/utils.test.ts b/packages/core/src/sso/OidcConnector/utils.test.ts index 1c0150d10..689313c9c 100644 --- a/packages/core/src/sso/OidcConnector/utils.test.ts +++ b/packages/core/src/sso/OidcConnector/utils.test.ts @@ -163,7 +163,6 @@ describe('fetchToken', () => { body: new URLSearchParams({ grant_type: 'authorization_code', code: data.code, - client_id: oidcConfig.clientId, redirect_uri: redirectUri, }).toString(), headers: { diff --git a/packages/core/src/sso/OidcConnector/utils.ts b/packages/core/src/sso/OidcConnector/utils.ts index 0522cb3ab..1583d6d06 100644 --- a/packages/core/src/sso/OidcConnector/utils.ts +++ b/packages/core/src/sso/OidcConnector/utils.ts @@ -56,25 +56,23 @@ export const fetchOidcConfig = async ( } }; +type HandleTokenExchangePayload = { + code: string; + clientId: string; + clientSecret: string; + redirectUri?: string; +}; + export const handleTokenExchange = async ( tokenEndpoint: string, - { - code, - clientId, - clientSecret, - redirectUri, - }: { - code: string; - clientId: string; - clientSecret: string; - redirectUri?: string; - } + { code, clientId, clientSecret, redirectUri }: HandleTokenExchangePayload ) => { const tokenRequestParameters = new URLSearchParams({ grant_type: 'authorization_code', code, - client_id: clientId, ...(redirectUri ? { redirect_uri: redirectUri } : {}), + // No need to pass `client_id` and `client_secret` as it is already in the Authorization header + // For some providers like Okta, passing `client_id` in the body while using client credentials authorization header will cause an error }); const headers = {