XX_auth example #1894
Replies: 28 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? |
Beta Was this translation helpful? Give feedback.
-
|
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? |
Beta Was this translation helpful? Give feedback.
-
|
No, it's a good timing to try and learn what's good and bad. |
Beta Was this translation helpful? Give feedback.
-
|
FYI, check this thread: https://twitter.com/sebmarkbage/status/1765414733820129471 |
Beta Was this translation helpful? Give feedback.
-
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. |
Beta Was this translation helpful? Give feedback.
-
|
@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);
}
}; |
Beta Was this translation helpful? Give feedback.
-
|
How do you call the |
Beta Was this translation helpful? Give feedback.
-
|
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 RegistartionFormand 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; |
Beta Was this translation helpful? Give feedback.
-
|
Hmm, it looks fine to me. You may need to find a difference from 05_actions example. Wait, that example uses |
Beta Was this translation helpful? Give feedback.
-
|
There is no exiting example using getContext in a server function or a server component. How can I help to find this problem? |
Beta Was this translation helpful? Give feedback.
-
|
See #584 |
Beta Was this translation helpful? Give feedback.
-
|
#587 will fix. |
Beta Was this translation helpful? Give feedback.
-
|
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? |
Beta Was this translation helpful? Give feedback.
-
I'm not sure if this is going to be a proper way, but if a thrown object has |
Beta Was this translation helpful? Give feedback.
-
|
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. |
Beta Was this translation helpful? Give feedback.
-
#576 (comment) But, for now, if you need a route level access check, you can try it with middleware. It's the only option. |
Beta Was this translation helpful? Give feedback.
-
|
@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. |
Beta Was this translation helpful? Give feedback.
-
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 |
Beta Was this translation helpful? Give feedback.
-
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. |
Beta Was this translation helpful? Give feedback.
-
|
Hi there, I just dropped it. It almost works well but WIP. |
Beta Was this translation helpful? Give feedback.
-
|
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.) |
Beta Was this translation helpful? Give feedback.
-
|
Hi, @daanlenaerts !
https://oslo.js.org/reference/password/ Anyway, I resolved how to set it up in vite.config.ts to use Argon2, |
Beta Was this translation helpful? Give feedback.
-
|
Interesting, excluding it from Vite seems like a good solution to these kinds of issues. Thanks for sharing @t6adev! |
Beta Was this translation helpful? Give feedback.
-
|
Here's a quick example that uses better-auth - https://github.com/rmarscher/waku-auth-example |
Beta Was this translation helpful? Give feedback.
-
Can anyone here have a quick review on it? |
Beta Was this translation helpful? Give feedback.
-
It's nice and minimal. I left a quick issue on the repo for a small library question. @rmarscher do you think it'd be helpful to show a pattern of "protected" vs "public" routes using group layouts or something like that. it looks pretty trivial to implement from my pov, but would probably be good as an example for newer users. |
Beta Was this translation helpful? Give feedback.
-
|
I reviewed the better-auth NextJS guide and incorporated some ideas in the example - including a better-auth plugin for cookie handling. I created an integration guide and submitted an upstream PR. https://github.com/rmarscher/better-auth/blob/feat/waku-integration-guide/docs/content/docs/integrations/waku.mdx |
Beta Was this translation helpful? Give feedback.
-
|
better-auth/better-auth#7233 🎉 I think it's the most updated example. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
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.
Beta Was this translation helpful? Give feedback.
All reactions