-
-
Notifications
You must be signed in to change notification settings - Fork 125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
XX_auth example #576
Comments
Thanks for asking. No, you don't miss anything. I've been thinking some auth example would be necessary too. I'm not sure if middleware will be a final solution (and I don't think #329 will be for auth anyway), but yes, it's the only solution for now. Let's see how much we can go with it. Let's say if we somehow checked credential in middleware, what would be the expected response? Would be easy for redirect for HTML, and 401 Forbidden for RSC, but too limited? |
Currently there are two common approaches when going to a page which needs auth:
The middleware will check the credentials and will provide user data in the context. It is than up to the server component to check this context and decide based on the permissions of the user what to do - e.g. show alternative content, a login or redirect to a login page. I could try a prototype - or do you think I should wait for a later release of WAKU? |
No, it's a good timing to try and learn what's good and bad. |
FYI, check this thread: https://twitter.com/sebmarkbage/status/1765414733820129471 |
I do not now any framework where auth is not handled at the middleware. The tweet does not offer a solution as you cannot show parts of the layout and check only at the data layer for permission. My current implementation ist doing this in the middleware:
He is right, that accessing a database in the middleware is a performance problem but this is only the case for sessions which are database bound. Token based session do not need any database. The routing of the authenticated or not authenticated users should be handled by the router or in the page component. |
@dai-shi How can I read and write to the context from a server function. Currently I get this error when I use the
'use server';
import { pool } from "./lib/db.js";
import { lucia } from "./lib/auth.js";
import { generateId ,Session, User} from "lucia";
import { Argon2id } from "oslo/password";
import {getContext} from 'waku/server';
export const register = async (formData: FormData) => {
const name = formData.get('name');
const email = formData.get('email');
const password = formData.get('password');
const hashedPassword = await new Argon2id().hash(password);
const userId = generateId(15);
try {
const db = await pool.getConnection();
await db.execute(`INSERT INTO user (id, username, password,email,name) VALUES (?, ?, ?,?,?)`, [userId, email, hashedPassword, email, name]);
const session = await lucia.createSession(userId, {});
const context = getContext<{ session: Session,user: User }>();
context.session = session;
} catch (e) {
console.log(e);
}
}; |
How do you call the |
except for the context - my code is working as expected as a server function: /// <reference types="react/canary" />
/// <reference types="react-dom/canary" />
'use client';
import { useFormStatus } from 'react-dom';
const RegisterButton = () => {
const { pending } = useFormStatus();
return (
<>
<button disabled={pending} type="submit">
Register
</button>
{pending ? 'Pending...' : null}
</>
);
};
const RegistartionForm = ({ register }) => {
return (
<div>
<h1>Registration Form</h1>
<form action={register} >
<div>
<label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" required />
</div>
<div>
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" required />
</div>
<div>
<label htmlFor="password">Password:</label>
<input type="password" id="password" name="password" required />
</div>
<div>
<RegisterButton />
</div>
</form>
</div>
)
}
export default RegistartionForm and here is the root server component: import RegistrationForm from "../components/RegistrationForm.js";
import { register } from "../func.js";
const RegistrationPage = () => {
return (
<RegistrationForm register={register} />
);
}
export default RegistrationPage; |
Hmm, it looks fine to me. You may need to find a difference from 05_actions example. Wait, that example uses |
There is no exiting example using getContext in a server function or a server component. How can I help to find this problem? |
See #584 |
#587 will fix. |
I have been building a Middleware-based example to facilitate cookie-based authentication. I’m not sure, however, what the best way to protect routes would be. Does any of you have a suggestion? Checking the request pathname against a set of protected routes is not great, as this doesn’t cover server components that are fetched by client-side React. With regards to auth in server actions, is there already a way to set a 401 header if the user is not authorized? |
I'm not sure if this is going to be a proper way, but if a thrown object has |
Great, I’ll experiment with that! It’s especially useful in server actions. The main thing I’m stuck on is properly validating route access for server components. I have tried checking access inside of a server component, but that just doesn’t feel right. Throwing an error at that point also crashes the server. But at any rate, existing frameworks don’t seem to do it this way either. It seems most natural to me to check access on a route level, through the route configuration or a middleware. Do you have any direction you would like this to go in? If I figure out a good way to do this I’d love to contribute it, as an example or a low-level integrated API in Waku. |
#576 (comment) But, for now, if you need a route level access check, you can try it with middleware. It's the only option. |
@daanlenaerts access logic for a server function is similar to validation. What you need there is a context to the current authenticated user role which you then add to your ORM call which also handles the access rights. Converting a session token in a cookie to a user needs to happen in the middleware. |
Makes sense!
For sure, I've got that working already. The DX for it isn't great though at the moment, I'll have to figure out a way to improve what happens when access is not granted. Possible the |
Have a look at graphQL or tRPC - both of them handle this great. You will need a custom Error Class you throw on the server and handle this on the client. |
Hi there, I just dropped it. It almost works well but WIP. |
This might be a little off topic, but @t6adev, I was reading through your code and saw you are using Scrypt instead of Argon2 as a hashing algorithm. In my experiments I also noticed Argon2 is not working when the project is built, neither is Bcrypt. Do you have any ideas or pointers on how to make Vite work with Argon2 or Bcrypt? (Bcrypt doesn't seem to work as the Node crypto module cannot be resolved.) |
Hi, @daanlenaerts !
https://oslo.js.org/reference/password/ Anyway, I resolved how to set it up in vite.config.ts to use Argon2,
|
Interesting, excluding it from Vite seems like a good solution to these kinds of issues. Thanks for sharing @t6adev! |
I am looking into creating a simple auth example with a home page and some protected sub routes.
Do I miss something, but:
I know that #329 was post boned, but today using an OAuth 2 authorization flow is more common than using a password database.
I still would start if I get a hint on how to deal with 1. and would use Lucia as the auth layer in the middleware. Maybe I can use the middleware to implement the callback and do not need #329.
The text was updated successfully, but these errors were encountered: