DEV Community

Kamran Khan
Kamran Khan

Posted on

My register endpoint returns a token — one fewer round trip, one better UX

Here's a small decision in my starter kit that I keep getting asked about: POST /api/auth/register returns a 201 with both the user object and an auth token. Not just "user created, now go log in." The user is authenticated the moment they register.

Why? Think about the actual flow. A new user fills in name, email, password, hits submit. If the response only confirms creation, the frontend has to immediately fire a second request to /api/auth/login with the same credentials, wait, get the token, store it, and then redirect. That's a round trip that serves no one — the server already validated everything it needs to validate. The register endpoint created the user; issuing a token for a user you just created is not a security hole, it's common sense.

The implementation is boring on purpose:

$user = User::create([
    'name'  => $request->validated('name'),
    'email' => $request->validated('email'),
    'password' => $request->validated('password'),
    'role'  => 'user',
]);

$token = $user->createToken('auth-token')->plainTextToken;

return response()->json([
    'user'  => new UserResource($user),
    'token' => $token,
], 201);
Enter fullscreen mode Exit fullscreen mode

Three things worth noticing. First, the role is hardcoded to 'user' — it comes from the server, not the request. The test suite literally posts role: admin and asserts the user is still created as a regular user. Second, the user goes through UserResource, so the shape the frontend receives on register is identical to login, /me, and every admin response — one contract, no surprises. Third, it's 201, because a resource was created. Status codes are part of the contract too; the frontend's error handling depends on them.

On the React side, this makes the register page trivial: post, store the token from the response, drop the user into context, navigate to the dashboard. No second request, no "please log in with the account you just created" awkwardness — which, honestly, always felt broken to me as a user. Every SaaS product you've ever signed up for logs you in immediately. Your starter kit should behave like the products you admire, not like a textbook.

And because the token issuance happens in the same request, there's one fewer place for the frontend to mishandle auth state. Fewer moving parts, fewer bugs. That's the whole philosophy: the boring path is usually the right one.


This is from my Laravel + React SaaS Starter Kit ($19, one-time) — Sanctum auth with register/login/logout/me, role-based access, and a React dashboard that consumes it all. The auth layer is done; you build the product.

Top comments (2)

Collapse
 
elijahbrown profile image
Elijah Brown •

Agree on returning the token, and the test that posts role admin is a nice touch. One thing worth deciding early: what that fresh token is allowed to do before the email is confirmed. We issue it with the same shape but gate a few actions (inviting teammates, generating API keys) on a confirmed flag in the user resource. The frontend already reads that resource on every route, so it costs nothing extra and stops throwaway accounts from doing anything interesting.

Collapse
 
kamrankhandev profile image
Kamran Khan •

This is the exact follow-up I should have written in the post itself, honestly. The token shape staying identical is the right call — the frontend never has to branch on "which kind of session is this," it just reads the flag.

One thing I'd add: enforce the gating server-side with a small middleware on the sensitive routes, not just in the React layer. A 403 with a clear error code like email_not_verified lets the frontend intercept it globally and show the verification nudge, so the flag in the resource becomes a UI hint and the real enforcement stays where it belongs. I trust the client to render the right screen, not to make the security decision.

And the balance you describe is the hard part — gate the expensive/destructive actions (API keys, invites, anything that sends mail) but let people explore the product freely. Too much gating in the first five minutes and you lose them before they see any value.