Fix: login cookies and refresh token
This commit is contained in:
parent
1b2673fc93
commit
76fa4872f1
7 changed files with 80 additions and 55 deletions
34
src/lib/accessToken.ts
Normal file
34
src/lib/accessToken.ts
Normal 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;
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: "/" },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue