mirror of
https://github.com/logto-io/logto.git
synced 2025-01-27 21:39:16 -05:00
refactor(core): add OIDCRequestError (#214)
* refactor(core): add OIDCRequestError inplement OIDCRequestError to normalize OIDCProviderError * fix(coer): cr fix code review update
This commit is contained in:
parent
eac74fae40
commit
a5c9bf61d7
4 changed files with 98 additions and 10 deletions
65
packages/core/src/errors/OIDCRequestError/index.ts
Normal file
65
packages/core/src/errors/OIDCRequestError/index.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { LogtoErrorCode, LogtoErrorI18nKey } from '@logto/phrases';
|
||||
import { RequestErrorBody } from '@logto/schemas';
|
||||
import decamelize from 'decamelize';
|
||||
import i18next from 'i18next';
|
||||
import pick from 'lodash.pick';
|
||||
import { errors } from 'oidc-provider';
|
||||
|
||||
export default class OIDCRequestError extends Error {
|
||||
code: LogtoErrorCode;
|
||||
status: number;
|
||||
expose: boolean;
|
||||
data: unknown;
|
||||
|
||||
constructor(error: errors.OIDCProviderError) {
|
||||
const {
|
||||
status = 400,
|
||||
message,
|
||||
error_description,
|
||||
error_detail,
|
||||
name,
|
||||
expose = true,
|
||||
constructor,
|
||||
...interpolation
|
||||
} = error;
|
||||
|
||||
super(message);
|
||||
|
||||
switch (constructor) {
|
||||
case errors.InvalidScope:
|
||||
case errors.InvalidTarget:
|
||||
case errors.InvalidToken:
|
||||
case errors.InvalidClientMetadata:
|
||||
case errors.InvalidGrant:
|
||||
this.code = `oidc.${decamelize(name)}` as LogtoErrorCode;
|
||||
this.message = i18next.t<string, LogtoErrorI18nKey>(`errors:${this.code}`, interpolation);
|
||||
break;
|
||||
case errors.SessionNotFound:
|
||||
this.code = 'session.not_found';
|
||||
this.message = i18next.t<string, LogtoErrorI18nKey>(`errors:${this.code}`, interpolation);
|
||||
break;
|
||||
case errors.InsufficientScope:
|
||||
this.code = 'oidc.insufficient_scope';
|
||||
this.message = i18next.t<string, LogtoErrorI18nKey>(`errors:${this.code}`, {
|
||||
scopes: error_detail,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.code = 'oidc.provider_error';
|
||||
this.message = i18next.t<string, LogtoErrorI18nKey>(`errors:${this.code}`, {
|
||||
message: this.message,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
this.status = status;
|
||||
this.expose = expose;
|
||||
|
||||
// Original OIDCProvider Error description and details are provided in the data field
|
||||
this.data = { error_description, error_detail };
|
||||
}
|
||||
|
||||
get body(): RequestErrorBody {
|
||||
return pick(this, 'message', 'code', 'data');
|
||||
}
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
import { LogtoErrorCode } from '@logto/phrases';
|
||||
import { RequestErrorBody } from '@logto/schemas';
|
||||
import decamelize from 'decamelize';
|
||||
import { Middleware } from 'koa';
|
||||
import { errors } from 'oidc-provider';
|
||||
import { NotFoundError } from 'slonik';
|
||||
|
||||
import OIDCRequestError from '@/errors/OIDCRequestError';
|
||||
import RequestError from '@/errors/RequestError';
|
||||
|
||||
export default function koaErrorHandler<StateT, ContextT>(): Middleware<
|
||||
|
@ -24,17 +23,14 @@ export default function koaErrorHandler<StateT, ContextT>(): Middleware<
|
|||
}
|
||||
|
||||
if (error instanceof errors.OIDCProviderError) {
|
||||
ctx.status = error.status;
|
||||
ctx.body = {
|
||||
message: error.error_description ?? error.message,
|
||||
// Assert error type of OIDCProviderError, code key should all covered in @logto/phrases
|
||||
code: `oidc.${decamelize(error.name)}` as LogtoErrorCode,
|
||||
data: error.error_detail,
|
||||
};
|
||||
const oidcError = new OIDCRequestError(error);
|
||||
ctx.status = oidcError.status;
|
||||
ctx.body = oidcError.body;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Slonik Error
|
||||
if (error instanceof NotFoundError) {
|
||||
const error = new RequestError({ code: 'entity.not_found', status: 404 });
|
||||
ctx.status = error.status;
|
||||
|
@ -43,6 +39,8 @@ export default function koaErrorHandler<StateT, ContextT>(): Middleware<
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Zod Error
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,8 +27,21 @@ const errors = {
|
|||
},
|
||||
oidc: {
|
||||
aborted: 'The end-user aborted interaction.',
|
||||
invalid_scope: 'Scope {{scopes}} is not supported.',
|
||||
invalid_scope: 'Scope {{scope}} is not supported.',
|
||||
invalid_scope_plural: 'Scope {{scopes}} are not supported.',
|
||||
invalid_token: 'Invalid token provided.',
|
||||
invalid_client_metadata: 'Invalid client metadata provided.',
|
||||
insufficient_scope: 'Access token missing requested scope {{scopes}}.',
|
||||
invalid_request: 'Request is invalid.',
|
||||
invalid_grant: 'Grant request is invalid.',
|
||||
invalid_redirect_uri:
|
||||
"`redirect_uri` did not match any of the client's registered `redirect_uris`.",
|
||||
access_denied: 'Access denied.',
|
||||
invalid_target: 'Invalid resource indicator.',
|
||||
unsupported_grant_type: 'Unsupported `grant_type` requested.',
|
||||
unsupported_response_mode: 'Unsupported `response_mode` requested.',
|
||||
unsupported_response_type: 'Unsupported `response_type` requested.',
|
||||
provider_error: 'OIDC Internal Error: {{message}}.',
|
||||
},
|
||||
user: {
|
||||
username_exists: 'The username already exists.',
|
||||
|
|
|
@ -31,6 +31,18 @@ const errors = {
|
|||
aborted: '用户终止了交互。',
|
||||
invalid_scope: '不支持的 scope: {{scopes}}。',
|
||||
invalid_scope_plural: '不支持的 scope: {{scopes}}。',
|
||||
invalid_token: 'token 无效。',
|
||||
invalid_client_metadata: '无效 client metadata。',
|
||||
insufficient_scope: '请求 token 缺少一下权限: {{scopes}}。',
|
||||
invalid_request: '请求失败。',
|
||||
invalid_grant: '授权失败。',
|
||||
invalid_redirect_uri: '无效返回链接, 该 redirect_uri 未被此应用注册。',
|
||||
access_denied: '拒绝访问。',
|
||||
invalid_target: '请求资源无效。',
|
||||
unsupported_grant_type: '不支持的 grant_type。',
|
||||
unsupported_response_mode: '不支持的 response_mode。',
|
||||
unsupported_response_type: '不支持的 response_type。',
|
||||
provider_error: 'OIDC 错误: {{message}}。',
|
||||
},
|
||||
user: {
|
||||
username_exists: '用户名已存在。',
|
||||
|
|
Loading…
Add table
Reference in a new issue