Urgent.News

What's breaking now, across thousands of outlets.

Tech

An admin can't delete their own account: two lines of defense in my users destroy endpoint

I nearly locked myself out of my own admin panel once. Testing the user-delete button, clicked my own row out of habit, confirmed the modal without thinking. The account was gone. So were all its sessions — obviously — and I had to re-seed the database to get back in. The fix is two lines, and both belong on the backend, not in a confirm dialog. Frontend confirm dialogs are a suggestion. The API…

The author recounts a personal experience of inadvertently deleting their admin account due to a testing error. To prevent such incidents, they implemented two crucial lines of defense in their user-delete endpoint.

The first line of defense checks if the authenticated user is attempting to delete themselves. If so, the endpoint returns a 422 HTTP status code with a clear error message indicating that an account cannot be deleted by its owner. This check utilizes Eloquent's is() method, which compares the model's key and table, ensuring a proper comparison without getting confused by integer vs. string data types.

The second line of defense involves deleting the user's personal access tokens before deleting the user's account itself. Sanctum users, for instance, have separate token rows in a different table. Simply deleting the user without first removing their tokens could leave orphaned tokens, which is a security risk. By deleting the tokens first, the endpoint guarantees that no abandoned tokens remain, and it also ensures that any active sessions on different devices are terminated simultaneously with the user's deletion.

These two lines of defense are implemented server-side and are not circumvented by frontend measures, such as disabling the delete button on the user's own row. The author emphasizes that endpoints are the ultimate safeguard against unauthorized actions, as they are called by various components, including scripts, tests, and mobile applications.

The author claims that this approach, implemented in their Laravel + React SaaS Starter Kit, ensures a trustworthy foundation for their applications. They offer the starter kit for purchase at $19 for a one-time fee.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

My users table reads one pagination contract: paginate(15), withQueryString, and a React pager that trusts meta

The first admin panel I built fetched all users, dumped them into state, and sliced pages client-side. It worked until a client hit 2,000 users and the list page took eleven seconds to load.

  • Implemented server-side pagination with Laravel's paginate(15) for 2,000+ users
  • React pager relied on backend meta data, fetching users based on page and meta
  • Consistent pagination contract extended to all admin panels in Laravel + React SaaS Starter Kit

How I built a live halftone portrait in React with just Canvas 2D

My portfolio is set like a newspaper, so my photo couldn't just be a photo. I wanted it to look like a printed halftone: a grid of dots, bigger where the picture is dark and smaller where it's light.

  • Image transformed into low-resolution grid of dots using Canvas 2D API
  • Dot radius determined by sample darkness with applied tone curve
  • Cursor interaction causes dots to swell and recede in a breathing effect

Pushing Beats Polling Explained: Live Poll Trust Above a Handful of Viewers

Short answer: pushing beats polling above a handful of viewers because one state change should not trigger repeated reads for every screen, but treat delivery as an optimization, not as authorization.

  • Pushing poll results, not polling, reduces unnecessary load and scaling issues with more viewers
  • Trust must be established independently of transport layer for untrusted clients
  • Small, immutable poll state snapshots enable reconnects with correct, up-to-date view

More from Saturday 17 October →