So, here is the problem, I want to get an user based on their credentials, the process a initially followed:
- Pass user email/password from a html form
- In server side, using node-appwrite with an api_key, make session token out .secret from 1, save it in a cookie
- I don't think I can use this cookie on my server instance, right? I get this: 'API key and session used in the same request. Use either setSession or setKey. Learn about which authentication method to use in the SSR docs: https://appwrite.io/docs/products/auth/server-side-rendering'
Is the correct approach just create another new Client() instance from Appwrite, just to grab this user information? And effectively checking permissions and such just when I'm making requests on DB, by always using a new Client() with an API key?
My objective with this is that: any data that is being saved on a Appwrite has to be sanitized in server side, for example, lets say that I want to save an username for a game character, it can't have any special symbols, only letter and numbers, without the server side validation, people can pass anything by just grabbing their .secret cookie and making direct requests for Appwrite.
PS I'm aware that the allowed characters in Appwrite are: alphanumeric, hyphen, non-leading underscore, period, but it's just to get an idea.
Here is some code:
// server instance, has an api key and full access, but can't use a session to grabe an user.
import { Account, Client, Databases } from 'node-appwrite';
import { API_KEY } from '$env/static/private';
import { PUBLIC_ENDPOINT, PUBLIC_PROJECT } from '$env/static/public';
const serverSession = new Client();
serverSession
.setEndpoint(PUBLIC_ENDPOINT)
.setProject(PUBLIC_PROJECT)
.setKey(API_KEY);
const account = new Account(serverSession);
const databases = new Databases(serverSession);
export { account, databases, serverSession }
// part of my login code, email and passwords comes from the frontend.
import { account } from '$lib/server/appwrite';
// ... more verification code ...
const { email, password } = result.data;
const res = await account.createEmailPasswordSession(email, password);
cookies.set('session', res.secret, {
path: '/',
httpOnly: true,
sameSite: 'strict'
});
// a hook, this run at each request, I can't grab the user here
const auth: Handle = async ({ event, resolve }) => {
const session = event.cookies.get('session');
if (!session) {
if (event.url.pathname !== '/login') throw redirect(303, '/login');
return await resolve(event);
}
try {
serverSession.setSession(session);
const user = await account.get();
console.log(user);
event.locals.user = user;
} catch (error) {
event.cookies.delete('session', { path: '/' });
if (event.url.pathname !== '/login') throw redirect(303, '/login');
}
return await resolve(event);
};
What framework are you using for your website?
it seems like you are using next.js?
Sveltekit
ahh
So, what you should do is the following:
- Login -> create cookie
- With cookie -> get value from cookie on the server, which should only have the value, use .setSession(tokenHere) as your client
I see you are using .setKey
For example in my project (next.js, but same principle):
const headersList = headers()
const cookieHeader = headersList.get('cookie')
const cookies = cookieHeader ? cookieHeader.split('; ') : []
const sessionCookie = cookies.find((cookie) =>
cookie.startsWith(
`a_session_${process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID}`
)
)
const client = new Client()
.setEndpoint(`${process.env.NEXT_PUBLIC_API_URL}/v1`)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
if (sessionCookie) {
client.setSession(sessionCookie.split('=')[1])
}
what you are saying is, from what I said:
Is the correct approach just create another new Client()... etc, etc, etc
is this correct?
you are saying i shoudl create a new client instance just to grab this data
You should grab the cookie and then set a client instance
The thing about SSR, is nothing is saved client side.
So what I do:
export async function createSessionServerClient() {
const headersList = headers()
const cookieHeader = headersList.get('cookie')
const cookies = cookieHeader ? cookieHeader.split('; ') : []
const sessionCookie = cookies.find((cookie) =>
cookie.startsWith(
`a_session_${process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID}`
)
)
const client = new Client()
.setEndpoint(`${process.env.NEXT_PUBLIC_API_URL}/v1`)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
if (sessionCookie) {
client.setSession(sessionCookie.split('=')[1])
}
return {
get account() {
return new Account(client)
},
get teams() {
return new Teams(client)
},
get databases() {
return new Databases(client)
},
get storage() {
return new Storage(client)
},
get functions() {
return new Functions(client)
},
get messaging() {
return new Messaging(client)
},
get locale() {
return new Locale(client)
},
get avatars() {
return new Avatars(client)
},
}
}
And then on every page, let's say you want to use database:
const { databases } = await createSessionServerClient()
So for each request you are making with "databases", you make sure to set the client, which the token you basically get from your cookie
huhum...
so, i should have something like, sessionClient and adminClient, each a different new Client() instance, being adminClient one that has setKey
Yes
i see
This is how my entire appwrite-session.ts file looks like:
createSessionClient is the same as createSessionServerClient, but it uses request as a parameter for the /api routes, which is basically CSR -> SSR -> SSR, but that's kind of a special case..
but you can see the createAdminSession and createSessionServerClient
i see, this makes sense, I had some misconceptions, but this cleared it
thanks a lot
Great to hear!
If this solved your issue, please add [SOLVED] at the beginning of the title.
Happy appwriting! :appwriterocket:
Recommended threads
- Cant configure email templates
i configure it on the console, and when i send the OTP, it sends with appwrite's email (instead of custom smtp) and with the branding, but i have the Pro (educa...
- Need help with createExecution function
Hi, Need some help understanding createExecution. When requesting function execution via createExecution, the function handler arguments are incorrect and rese...
- Query Appwrite
Hello, I have a question regarding Queries in Appwrite. If I have a string "YYYY-MM", how can I query the $createdAt column to match this filter?