T
tRPC

Can set cookie with trpc?

Can set cookie with trpc?

DDxD11/13/2023
I tried to create a full authentication system in trpc using jwt and refresh token I find that is not quite okay to create authentication with trpc Can you suggest me a better way how I can achieve authentication in trpc project ?
BBeBoRE11/13/2023
Why do you find it not okay to create auth with tRPC? The most simple solution would be to implement a route with which you can login, which then sets a JWT cookie. And then create a protected procedure that checks someone’s JWT, Most projects will be using auth frameworks like LuciaAuth, NextAuth or Clerk etc.
DDxD11/13/2023
I can not send cookie via trpc, I tried a lot(if I use with express) I know with clerk to do auth, I am just curious to do it with jwt
BBeBoRE11/14/2023
You can set cookies in Express using res.cookies So as long as you give tRPC access to the res object, you can send cookies Otherwise you might want to send the JWT in the body of your response and send it as a header with every request
DDxD11/14/2023
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { TRPCError } from '@trpc/server';
import { db } from 'db';
import jwt from 'jsonwebtoken';
import { checkSamePassword } from 'utils/hash/checkSamePassword';
import keys from 'utils/secret/keys';
import { z } from 'zod';

import { router, publicProcedure } from '..';

export const loginRouter = router({
login: publicProcedure
.input(
z.object({
email: z.string().nonempty('Email is required').email('Invalid email address'),
password: z.string().nonempty('Password is required').min(6),
}),
)
.query(async ({ ctx, input: { email, password } }) => {
const user = await db.user.findOne({ email: email });
const validatePassword = await checkSamePassword(password, user?.password);
if (!user || !validatePassword) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Email or password is not valid, please try again.',
});
} else {
const token = jwt.sign({ _id: user._id }, keys.jwtSecret, { expiresIn: '1h' });
const expirationDate = new Date(Date.now() + 900000);

ctx.res.cookie('token', token, {
expires: expirationDate,
httpOnly: true,
sameSite: 'None', /
path: '/',
});
}
}),
});
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { TRPCError } from '@trpc/server';
import { db } from 'db';
import jwt from 'jsonwebtoken';
import { checkSamePassword } from 'utils/hash/checkSamePassword';
import keys from 'utils/secret/keys';
import { z } from 'zod';

import { router, publicProcedure } from '..';

export const loginRouter = router({
login: publicProcedure
.input(
z.object({
email: z.string().nonempty('Email is required').email('Invalid email address'),
password: z.string().nonempty('Password is required').min(6),
}),
)
.query(async ({ ctx, input: { email, password } }) => {
const user = await db.user.findOne({ email: email });
const validatePassword = await checkSamePassword(password, user?.password);
if (!user || !validatePassword) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Email or password is not valid, please try again.',
});
} else {
const token = jwt.sign({ _id: user._id }, keys.jwtSecret, { expiresIn: '1h' });
const expirationDate = new Date(Date.now() + 900000);

ctx.res.cookie('token', token, {
expires: expirationDate,
httpOnly: true,
sameSite: 'None', /
path: '/',
});
}
}),
});
in my browser in cookie i can not see token @BeBoRE
BBeBoRE11/14/2023
You are creating a query, this should be a mutation If you changed that and it still doesn't work, see if you see the set-cookie header in your response headers
DDxD11/14/2023
okay, i will change it to mutation i let you know if it works
BBeBoRE11/14/2023
What is the raw response for the happy flow?
DDxD11/15/2023
? @BeBoRE i modigy tu mutation
DDxD11/15/2023
No description
DDxD11/15/2023
No description
DDxD11/15/2023
nothing
BBeBoRE11/15/2023
None specifies that cookies are sent on both originating and cross-site requests, but only in secure contexts (i.e., if SameSite=None then the Secure attribute must also be set). If no SameSite attribute is set, the cookie is treated as Lax.
None specifies that cookies are sent on both originating and cross-site requests, but only in secure contexts (i.e., if SameSite=None then the Secure attribute must also be set). If no SameSite attribute is set, the cookie is treated as Lax.
Using HTTP cookies SameSite=None only works in a secure context with HTTPS, you probably want to set that attribute to lax which is the default
DDxD11/15/2023
Ok Still now idea how to solve it Only idea that I used is when I send token on client, I use some js cookie or smt like that and from there I save it to cookie
BBeBoRE11/15/2023
Pretty sure if you remove sameSite: 'None' it should set the cookie correctly, also in the screenshot you send it looks like if you use my cookie as the cookie name, I don't believe you can have spaces in your cookie
DDxD11/16/2023
Ok, I will check it @BeBoRE
import { TRPCError } from '@trpc/server';
import { db, User } from 'db';
import jwt from 'jsonwebtoken';
import { hashPassword } from 'utils/hash/hashPassword';
import { keys } from 'utils/secret/keys';
import { z } from 'zod';

import { router, publicProcedure } from '..';

export const registerRouter = router({
register: publicProcedure
.input(
z.object({
email: z.string().nonempty('Email is required').email('Invalid email address'),
password: z.string().refine((value) => value.length >= 6, {
message: 'Password must contain at least 6 characters',
}),
confrimPassword: z.string().refine((value) => value.length >= 6, {
message: 'Password must contain at least 6 characters',
}),
}),
)
.mutation(async ({ ctx, input: { email, password, confrimPassword } }) => {
const checkUserExist = await db.user.findOne({ email: email });
if (checkUserExist) {
throw new TRPCError({
code: 'CONFLICT',
message: `Already exists an account with this ${email}, please try to log in`,
});
}
if (!password || password.length < 6 || password.length !== confrimPassword.length) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: `Password must contains at least 6 characters`,
});
}
const user = await db.user.findOne({ email: email });
const token = jwt.sign({ _id: user?._id }, keys.jwtSecret, { expiresIn: '5min' });
ctx.res.cookie('session_token', token, { httpOnly: true });
const hashedPassword = await hashPassword(password);
const newUser: User = { email, password: hashedPassword };
await db.user.insertOne(newUser);
return newUser;
}),
});
import { TRPCError } from '@trpc/server';
import { db, User } from 'db';
import jwt from 'jsonwebtoken';
import { hashPassword } from 'utils/hash/hashPassword';
import { keys } from 'utils/secret/keys';
import { z } from 'zod';

import { router, publicProcedure } from '..';

export const registerRouter = router({
register: publicProcedure
.input(
z.object({
email: z.string().nonempty('Email is required').email('Invalid email address'),
password: z.string().refine((value) => value.length >= 6, {
message: 'Password must contain at least 6 characters',
}),
confrimPassword: z.string().refine((value) => value.length >= 6, {
message: 'Password must contain at least 6 characters',
}),
}),
)
.mutation(async ({ ctx, input: { email, password, confrimPassword } }) => {
const checkUserExist = await db.user.findOne({ email: email });
if (checkUserExist) {
throw new TRPCError({
code: 'CONFLICT',
message: `Already exists an account with this ${email}, please try to log in`,
});
}
if (!password || password.length < 6 || password.length !== confrimPassword.length) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: `Password must contains at least 6 characters`,
});
}
const user = await db.user.findOne({ email: email });
const token = jwt.sign({ _id: user?._id }, keys.jwtSecret, { expiresIn: '5min' });
ctx.res.cookie('session_token', token, { httpOnly: true });
const hashedPassword = await hashPassword(password);
const newUser: User = { email, password: hashedPassword };
await db.user.insertOne(newUser);
return newUser;
}),
});
DDxD11/16/2023
No description
No description
DDxD11/16/2023
i do not understand where i do wrong
import * as trpcExpress from '@trpc/server/adapters/express';
import cors from 'cors';
import * as dotenv from 'dotenv';
import express from 'express';
import { envCheck } from 'utils/check/env';

dotenv.config();
envCheck();

import { db } from './db/connection';
import { createContext } from './trpc/context';
import { appRouter } from './trpc/router';

const app = express();

app.use(cors());

app.use(
'/trpc',
trpcExpress.createExpressMiddleware({
router: appRouter,
createContext,
}),
);

const PORT = process.env.PORT;

db.connect()
.then(() => {
console.log('Successfully connected to MongoDB.');
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}.`);
});
})
.catch(() => {
console.log('Failed to connect to MongoDB. Exiting...');
process.exit(1);
});
import * as trpcExpress from '@trpc/server/adapters/express';
import cors from 'cors';
import * as dotenv from 'dotenv';
import express from 'express';
import { envCheck } from 'utils/check/env';

dotenv.config();
envCheck();

import { db } from './db/connection';
import { createContext } from './trpc/context';
import { appRouter } from './trpc/router';

const app = express();

app.use(cors());

app.use(
'/trpc',
trpcExpress.createExpressMiddleware({
router: appRouter,
createContext,
}),
);

const PORT = process.env.PORT;

db.connect()
.then(() => {
console.log('Successfully connected to MongoDB.');
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}.`);
});
})
.catch(() => {
console.log('Failed to connect to MongoDB. Exiting...');
process.exit(1);
});
nvm, i solve it
BBeBoRE11/16/2023
What was the issue?
DDxD11/17/2023
i forgot to add
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
}),
);
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
}),
);
when i create express be 🙂 i add that and now works fine
BBeBoRE11/17/2023
Ah the empty cors made it so that the cookie wasn’t being send with, ngl I have never understood CORS
DDxD11/17/2023
:))) 3 days for a fu….ing CORS

Looking for more? Join the community!

T
tRPC

Can set cookie with trpc?

Join Server
Recommended Posts
trying to understand how this worksso i'm looking at the t3 template that was made for me, and there seems to be a `trpc` folder that ccan't call nested routethis is the top level router: ```ts const appRouter = router({ hello: procedure.query(() => 'heltrpc authDid someone create a full auth system in trpc (with next js trpc react query prisma,jwt token, refreDifference between createTRPCNextAppDirServer, createTRPCNext and createTRPCProxyClient?Hey everyone. I struggle to understand the difference between these 3 TRPC functions when it come tWhat is the mutation error type?In the provider I want to set onError for all mutations: ```ts new QueryClient({ defauMerging two clients into oneI have two clients. One for react-query for client components and one for server components. I wannaIs it possible to only use WebSockets when necessary, otherwise use httpbatch or http?I have an application, and on certain pages I need live data. Is there a way to only have tRPC open Zod transform typesI have a zod type for our backend requirements that looks like this: ```javascript const ZCustomTypeuseQuery in App Router?I have a client component that I want to use useQuery in like in pages router, but only `query` is aTranform output data using middleware after handler has run - possible?As the title says, been trying for a couple of hours to modify the return type of the data using midCan we configure cache on a per-request basis?Hi! I’m a big fan of tRPC! I’ve been using it for quite some time. I actually have 2 questions: ## Error in tRPC with Clerk in t3-app routerHi guys, im trying to implement clerk auth in t3 app router. But it gives me this error when im tryiError when converting string from router.query to prisma DB enumHey yall, I'm working on a Next.js application using tRPC and Prisma, and I've encountered an invaliNext.js tRPC router separated to edge-runtime and node-runtimeI would like to separate server into two runtimes - most things can run on edge-runtime, but I have [How To?] Create a record in database on form submission...I have an application using trpc, Cloudfare D1 database, and trpc. I am trying to use a tamagui forHow to obfuscate data via transformerEnd user with adequate knowledge can easily copy JSON data in plain text from network requests in brResponse delay from TRPC using postgresqlI'm using TRPC as backend and for the database using postgresql so while creating using facing delayCapture TRPCClientError so that it does not show in the client's browser consoleIf a TRPCError is thrown from a router procedure, the client will receive a TRPCClientError that wilNetlify function EMFILEIf this is a dumb question just point me in the direction of the stackoverflow. I've scoured discorempty `input` object when using mutationWhen using `useQuery` I have no issues even with input but when using `useMutation`. The backend is