0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(core): refactor oidc error response query param (#6525)

refactor oidc error reponse query param
This commit is contained in:
simeng-li 2024-08-28 10:14:04 +08:00 committed by GitHub
parent 3d3a220306
commit 8beb758771
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 26 deletions

View file

@ -2,24 +2,22 @@
"@logto/core": patch
---
introduce new `error_code_key` query parameter in the `koaErrorHandler`.
introduce new `parse_error` query parameter flag. The value of `parse_error` can only be `false`.
By default, Logto uses `code` as the error code key in the error response body.
For some third-party connectors, like Google, `code` is considered as a reserved OIDC key,
can't be used as the error code key in the error response body. Any oidc error response body containing `code` will be rejected by Google.
By default, Logto returns the parsed error code and error description in all the `RequestError` error responses. This is to ensure the error responses are consistent and easy to understand.
To workaround this, we introduce a new `error_code_key` query parameter to customize the error code key in the error response body.
In the oidc requests, if the `error_code_key` is present in the query string, we will use the value of `error_code_key` as the error code key in the error response body.
However, when integrating Logto with Google OAuth, the error response body containing `code` will be rejected by Google. `code` is considered as a reserved OIDC key, can't be used as the error code key in the error response body.
To workaround this, we add a new `parse_error` query parameter flag. When parsing the OIDC error body, if the `parse_error` is set to false, only oidc error body will be returned.
example:
```curl
curl -X POST "http://localhost:3001/oidc/token?error_code_key=error_code"
curl -X POST "http://localhost:3001/oidc/token?parse_error=false"
```
```json
{
"error_code": "oidc.invalid_grant",
"error": "invalid_grant",
"error_description": "Invalid value for parameter 'code': 'invalid_code'."
}

View file

@ -97,9 +97,22 @@ export default function koaOidcErrorHandler<StateT, ContextT>(): Middleware<Stat
ctx.body = errorOut(error);
}
// Parse the `parse_error` from the query string.
// If the `parse_error` is set to false, only returns the original oidc error body.
// For some third-party connectors, like Google, `code` is considered as a reserved OIDC key,
// we can't return the error body containing `code` in the error response.
const queryParametersResult = z
.object({
parse_error: z.literal('false').optional(),
})
.safeParse(ctx.query);
const returnRawError =
queryParametersResult.success && queryParametersResult.data.parse_error === 'false';
// This is the only way we can check if the error is handled by the oidc-provider, because
// oidc-provider doesn't call `renderError` when the request prefers JSON response.
if (ctx.status >= 400 && isObject(ctx.body)) {
if (ctx.status >= 400 && isObject(ctx.body) && !returnRawError) {
const parsed = z
.object({
error: z.string(),
@ -113,26 +126,14 @@ export default function koaOidcErrorHandler<StateT, ContextT>(): Middleware<Stat
const code = isSessionNotFound(data.error_description)
? 'session.not_found'
: `oidc.${data.error}`;
const uri = errorUris[data.error];
// Parse the `error_code_key` from the query string.
// This is used to customize the error key in the response body.
// For some third-party connectors, like Google, `code` is considered as a reserved OIDC key,
// can't be used as the error code key in the error response body.
// We add `error_code_key` to the query string to customize the error key in the response body.
const errorKeyQueryResult = z
.object({
error_code_key: z.string().optional(),
})
.safeParse(ctx.query);
const errorKey = errorKeyQueryResult.success
? errorKeyQueryResult.data.error_code_key ?? 'code'
: 'code';
ctx.body = {
[errorKey]: code,
message: i18next.t(['errors:' + code, 'errors:oidc.provider_error_fallback'], { code }),
code,
message: i18next.t(['errors:' + code, 'errors:oidc.provider_error_fallback'], {
code,
}),
error_uri: uri,
...ctx.body,
};