@opengis/fastify-table
Version:
core-plugins
94 lines (93 loc) • 3.9 kB
JavaScript
import pgClients from "../../../../plugins/pg/pgClients.js";
import dataInsert from "../../../../plugins/crud/funcs/dataInsert.js";
import { sign, scryptHash } from "../../../../plugins/auth/funcs/jwt.js";
import authorizeUser from "../../../../plugins/auth/funcs/authorizeUser.js";
const getIp = (req) => (req.headers?.["x-real-ip"] ||
req.headers?.["x-forwarded-for"] ||
req.ip ||
req.connection?.remoteAddress ||
"")
.split(":")
.pop();
const expireMsec = 1000 * 60 * 60;
// ? Request example: http://localhost:3000/oauth/authorize?response_type=code&client_id=2835134164020233999&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Foauth%2Ftoken%3Fclient_id%3D2835134164020233999%26noredirect%3D1%26grant_type%3Dauthorization_code
// ? add &noredirect=1 to retrieve code via GET request or simply send POST requests
export default async function authorize(req, reply) {
const { pg = pgClients.client, query, body } = req;
const payload = req.method === "POST" ? body : query;
const { response_type, client_id, redirect_uri, scope } = payload;
if (response_type !== "code") {
return reply
.code(400)
.send({ error: "unsupported response_type", code: 400 });
}
if (!client_id) {
return reply
.code(400)
.send({ error: "not enough query params: client_id", code: 400 });
}
const q = `select owner_user_id, client_secret_hash, redirect_uris from oauth.clients where client_id=$1 and token_endpoint_auth_method=$2 and ${scope ? "$1=any(scopes)" : "1=1"}`;
const { owner_user_id: userId, client_secret_hash: secret, redirect_uris = [], } = pg.pk?.["oauth.clients"]
? await pg
.query(q, [client_id, "private_key_jwt"])
.then((el) => el.rows?.[0] || {})
: {};
if (!userId) {
return reply.code(400).send({ error: "invalid client id", code: 400 });
}
if (redirect_uri &&
Array.isArray(redirect_uris) &&
!redirect_uris.includes(redirect_uri)) {
return reply.code(400).send({ error: "invalid redirect_uri", code: 400 });
}
const user = pg.pk?.["admin.users"]
? await pg
.query("select * from admin.users where uid=$1 and enabled limit 1", [
userId,
])
.then((el) => el.rows[0])
: null;
if (!user) {
return reply.code(404).send({ error: "user not found", code: 404 });
}
const href1 = await authorizeUser(user, req, "jwt", expireMsec);
// Generate authorization code
const code = sign(userId, secret, expireMsec);
const tokenHash = await scryptHash(code);
const ip = getIp(req);
// disable access via old tokens
if (pg.pk?.["oauth.tokens"]) {
await pg.query("update oauth.tokens set revoked_at = now(), revocation_reason='refresh' where client_id=$1", [client_id]);
}
await dataInsert({
pg,
table: "oauth.tokens",
data: {
token_type: "access",
token_hash: tokenHash,
token_hint: code.slice(-6),
// jti: undefined,
client_id,
user_id: userId,
// issuer: undefined,
scopes: [scope].filter(Boolean),
// claims: undefined,
issued_at: new Date(),
expires_at: new Date(Date.now() + expireMsec),
// revoked_at: undefined,
// revocation_reason: undefined,
ip,
},
uid: userId,
});
const backUrl = redirect_uri ? `${redirect_uri}?code=${code}` : "";
const href = redirect_uri && !redirect_uri.includes("?")
? backUrl
: backUrl?.replace?.(/\?code=/, "&code=") || href1;
if (req.method === "POST" ||
payload.noredirect ||
process.env.NODE_ENV === "test") {
return reply.code(200).send(code);
}
return reply.redirect(href);
}