0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-13 21:30:30 -05:00
logto/packages/core/src/middleware/koa-auth.ts

69 lines
2.1 KiB
TypeScript
Raw Normal View History

2021-08-24 00:11:25 +08:00
import { IncomingHttpHeaders } from 'http';
2021-08-30 11:30:54 +08:00
import { UserInfo, userInfoSelectFields } from '@logto/schemas';
2021-08-15 23:39:03 +08:00
import { jwtVerify } from 'jose/jwt/verify';
2021-08-30 11:30:54 +08:00
import { MiddlewareType, Request } from 'koa';
2021-08-15 23:39:03 +08:00
import { IRouterParamContext } from 'koa-router';
import pick from 'lodash.pick';
2021-08-30 11:30:54 +08:00
2021-08-24 00:11:25 +08:00
import { developmentUserId, isProduction } from '@/env/consts';
2021-08-30 11:30:54 +08:00
import RequestError from '@/errors/RequestError';
import { publicKey, issuer, adminResource } from '@/oidc/consts';
import { findUserById } from '@/queries/user';
import assert from '@/utils/assert';
2021-08-15 23:39:03 +08:00
export type WithAuthContext<ContextT extends IRouterParamContext = IRouterParamContext> =
ContextT & {
user: UserInfo;
};
2021-08-14 21:39:37 +08:00
const bearerTokenIdentifier = 'Bearer';
2021-08-14 21:39:37 +08:00
2021-08-24 00:11:25 +08:00
const extractBearerTokenFromHeaders = ({ authorization }: IncomingHttpHeaders) => {
assert(
authorization,
new RequestError({ code: 'auth.authorization_header_missing', status: 401 })
);
assert(
authorization.startsWith(bearerTokenIdentifier),
2021-08-24 00:11:25 +08:00
new RequestError(
{ code: 'auth.authorization_type_not_supported', status: 401 },
{ supportedTypes: [bearerTokenIdentifier] }
2021-08-24 00:11:25 +08:00
)
);
return authorization.slice(bearerTokenIdentifier.length + 1);
2021-08-24 00:11:25 +08:00
};
const getUserIdFromRequest = async (request: Request) => {
if (!isProduction && developmentUserId) {
return developmentUserId;
}
const {
payload: { sub },
} = await jwtVerify(extractBearerTokenFromHeaders(request.headers), publicKey, {
issuer,
audience: adminResource,
});
assert(sub, new RequestError({ code: 'auth.jwt_sub_missing', status: 401 }));
2021-08-24 00:11:25 +08:00
return sub;
};
2021-08-15 23:39:03 +08:00
export default function koaAuth<
2021-08-14 21:39:37 +08:00
StateT,
2021-08-15 23:39:03 +08:00
ContextT extends IRouterParamContext,
ResponseBodyT
>(): MiddlewareType<StateT, WithAuthContext<ContextT>, ResponseBodyT> {
2021-08-14 21:39:37 +08:00
return async (ctx, next) => {
2021-08-15 23:39:03 +08:00
try {
2021-08-24 00:11:25 +08:00
const userId = await getUserIdFromRequest(ctx.request);
const user = await findUserById(userId);
2021-08-15 23:39:03 +08:00
ctx.user = pick(user, ...userInfoSelectFields);
} catch {
throw new RequestError({ code: 'auth.unauthorized', status: 401 });
}
2021-08-14 21:39:37 +08:00
return next();
};
}