Fix: login cookies and refresh token

This commit is contained in:
Aron Malcher 2024-03-11 15:11:13 +01:00
parent 1b2673fc93
commit 76fa4872f1
Signed by: aronmal
GPG key ID: 816B7707426FC612
7 changed files with 80 additions and 55 deletions

34
src/lib/accessToken.ts Normal file
View file

@ -0,0 +1,34 @@
import { eq } from "drizzle-orm";
import db from "~/drizzle";
import { discordTokens } from "~/drizzle/schema";
import { discord } from "./auth";
const getAccessToken = async (userId: string) => {
let tokens = await db.query.discordTokens
.findFirst({
where: eq(discordTokens.userId, userId),
})
.execute();
if (tokens && new Date() >= tokens.expiresAt) {
const newTokens = await discord.refreshAccessToken(tokens.refreshToken);
tokens = (
await db
.update(discordTokens)
.set({
accessToken: newTokens.accessToken,
expiresAt: newTokens.accessTokenExpiresAt,
refreshToken: newTokens.refreshToken,
})
.where(eq(discordTokens.userId, userId))
.returning()
.execute()
)[0];
}
if (!tokens) return tokens;
return tokens;
};
export default getAccessToken;

View file

@ -2,7 +2,7 @@ import { createMiddleware } from "@solidjs/start/middleware";
import colors from "colors";
import fs from "fs";
import { verifyRequestOrigin } from "lucia";
import { appendHeader, getCookie, getHeader } from "vinxi/http";
import { getCookie, getHeader, setCookie } from "vinxi/http";
import { lucia } from "./lib/auth";
colors.enable();
@ -12,8 +12,8 @@ let started: boolean = false;
export default createMiddleware({
onRequest: async (event) => {
if (event.nativeEvent.node.req.method !== "GET") {
const originHeader = getHeader(event.nativeEvent, "Origin") ?? null;
const hostHeader = getHeader(event.nativeEvent, "Host") ?? null;
const originHeader = getHeader("Origin") ?? null;
const hostHeader = getHeader("Host") ?? null;
if (
!originHeader ||
!hostHeader ||
@ -24,8 +24,7 @@ export default createMiddleware({
}
}
const sessionId =
getCookie(event.nativeEvent, lucia.sessionCookieName) ?? null;
const sessionId = getCookie(lucia.sessionCookieName) ?? null;
if (!sessionId) {
event.nativeEvent.context.session = null;
event.nativeEvent.context.user = null;
@ -34,20 +33,22 @@ export default createMiddleware({
const { session, user } = await lucia.validateSession(sessionId);
if (session && session.fresh) {
appendHeader(
event.nativeEvent,
"Set-Cookie",
lucia.createSessionCookie(session.id).serialize(),
const sessionCookie = lucia.createSessionCookie(session.id);
setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes,
);
}
if (!session) {
appendHeader(
event.nativeEvent,
"Set-Cookie",
lucia.createBlankSessionCookie().serialize(),
const sessionCookie = lucia.createBlankSessionCookie();
setCookie(
sessionCookie.name,
sessionCookie.value,
sessionCookie.attributes,
);
}
console.log(3);
event.nativeEvent.context.session = session;
event.nativeEvent.context.user = user;
},

View file

@ -96,7 +96,6 @@ export async function GET(event: APIEvent): Promise<Response> {
expiresAt: tokens.accessTokenExpiresAt,
refreshToken: tokens.refreshToken,
})
.returning()
.execute();
const session = await lucia.createSession(
userId,

View file

@ -1,4 +1,3 @@
import { APIEvent } from "@solidjs/start/server";
import { generateState } from "arctic";
import httpStatus from "http-status";
import { setCookie } from "vinxi/http";
@ -7,13 +6,13 @@ import { discord } from "~/lib/auth";
if (typeof import.meta.env.PROD === "undefined")
throw new Error("No env PROD found!");
export async function GET(event: APIEvent) {
export async function GET() {
const state = generateState();
const url = await discord.createAuthorizationURL(state, {
scopes: ["identify", "guilds", "guilds.members.read"],
});
setCookie(event, "discord_oauth_state", state, {
setCookie("discord_oauth_state", state, {
path: "/",
secure: import.meta.env.PROD,
httpOnly: true,

View file

@ -4,15 +4,12 @@ import { appendHeader } from "vinxi/http";
import { lucia } from "~/lib/auth";
export const GET = async (event: APIEvent) => {
if (!event.nativeEvent.context.session) {
return new Error("Unauthorized");
}
await lucia.invalidateSession(event.nativeEvent.context.session.id);
appendHeader(
event,
"Set-Cookie",
lucia.createBlankSessionCookie().serialize(),
);
const { session } = event.nativeEvent.context;
if (!session) return new Error("Unauthorized");
await lucia.invalidateSession(session.id);
appendHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
return new Response(null, {
status: httpStatus.FOUND,
headers: { Location: "/" },

View file

@ -1,6 +1,5 @@
import { faToggleOff, faToggleOn } from "@fortawesome/pro-regular-svg-icons";
import { useLocation, useNavigate, useParams } from "@solidjs/router";
import { eq } from "drizzle-orm";
import moment from "moment-timezone";
import createClient from "openapi-fetch";
import {
@ -14,8 +13,7 @@ import { createStore } from "solid-js/store";
import { getRequestEvent } from "solid-js/web";
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
import Layout from "~/components/Layout";
import db from "~/drizzle";
import { discordTokens } from "~/drizzle/schema";
import getAccessToken from "~/lib/accessToken";
import { paths } from "~/types/discord";
import "../../styles/pages/config.scss";
@ -51,36 +49,39 @@ const getPayload = async (
const { user } = event.nativeEvent.context;
if (!user) return { success: false, message: "User not logged in!" };
const tokens = await db.query.discordTokens
.findFirst({
where: eq(discordTokens.userId, user.id),
})
.execute();
const tokens = await getAccessToken(user.id);
if (!tokens) return { success: false, message: "No discord access token!" };
const { GET } = createClient<paths>({
baseUrl: "https://discord.com/api/v10",
});
const guildsRequest = await GET("/users/@me/guilds", {
const { data: guildsData, error } = await GET("/users/@me/guilds", {
headers: { Authorization: `Bearer ${tokens.accessToken}` },
});
const channelsRequest = await GET("/guilds/{guild_id}/channels", {
params: {
path: {
guild_id: id,
const { data: channelsData, error: error2 } = await GET(
"/guilds/{guild_id}/channels",
{
params: {
path: {
guild_id: id,
},
},
headers: {
Authorization: `Bot ${import.meta.env.VITE_DISCORD_BOT_TOKEN}`,
},
},
headers: { Authorization: `Bot ${import.meta.env.VITE_DISCORD_BOT_TOKEN}` },
});
if (guildsRequest.error || channelsRequest.error) {
console.log(guildsRequest.error, channelsRequest.error, pathname);
);
if (error || error2) {
console.log("Discord api error:", { error, error2 });
console.log(error, error2, pathname);
return {
success: false,
message: "Error on one of the discord api requests!",
};
}
const guild = guildsRequest.data?.find((e) => e.id === id);
const guild = guildsData?.find((e) => e.id === id);
if (!guild)
return {
@ -95,7 +96,7 @@ const getPayload = async (
};
const channels: ReturnType<typeof initialValue>["guild"]["channels"] = [];
channelsRequest.data?.forEach((channel) => {
channelsData?.forEach((channel) => {
if (channel.type !== 0) return;
channels.push({
id: channel.id,

View file

@ -4,14 +4,12 @@ import {
faPlus,
} from "@fortawesome/pro-regular-svg-icons";
import { useLocation, useNavigate } from "@solidjs/router";
import { eq } from "drizzle-orm";
import createClient from "openapi-fetch";
import { For, createResource } from "solid-js";
import { getRequestEvent } from "solid-js/web";
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
import Layout from "~/components/Layout";
import db from "~/drizzle";
import { discordTokens } from "~/drizzle/schema";
import getAccessToken from "~/lib/accessToken";
import { paths } from "~/types/discord";
import "../../styles/pages/config.scss";
@ -43,11 +41,7 @@ const getPayload = async (): Promise<
const { user } = event.nativeEvent.context;
if (!user) return { success: false, message: "User not logged in!" };
const tokens = await db.query.discordTokens
.findFirst({
where: eq(discordTokens.userId, user.id),
})
.execute();
const tokens = await getAccessToken(user.id);
if (!tokens) return { success: false, message: "No discord access token!" };
const { GET } = createClient<paths>({
@ -58,7 +52,7 @@ const getPayload = async (): Promise<
});
if (error) {
console.log(error);
console.log("Discord api error:", { error });
return { success: false, message: "Error on discord api request!" };
}
console.log(pathname, "success");