Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use one authentication flow for both administrators and regular users, then make a separate server-side authorization decision for every protected page and action. A redirect to an admin dashboard or a hidden admin link is only navigation; neither grants nor secures access.

Authentication and authorization are separate jobs

Authentication establishes which account has signed in. Authorization checks whether that account may perform the requested action on the requested resource. After a successful login, the application should consult trusted account and permission data on the server before serving an admin route, changing a record, or exposing restricted information.

OWASP recommends checking permissions on every request and states, “For security purposes an application should be configured to deny access by default.” See the OWASP Authorization Cheat Sheet. A regular user must remain unauthorized even if they type an admin URL directly, alter a form field, or change an object identifier.

Choose how the application represents permissions

A small application can use one account table with a unique login name, password-hash field, and a role such as admin or user. That is an illustrative design, not a PHP requirement; the official PHP and OWASP guidance does not prescribe a particular schema or account-provisioning policy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Keep role assignment under trusted administrative control. Do not treat an is_admin value submitted by a public registration form as authoritative.
  • At login, load the account identity and permissions from the server-side record. A role value supplied or altered by a client is not proof of permission.
  • Role-based access control can be sufficient when permissions map cleanly to roles. If access depends on the user, a particular record, or context, an attribute- or relationship-based policy may fit better. OWASP discusses these approaches and recommends deciding on an access-control model early.

Store and verify passwords with PHP’s password APIs

When creating or changing a password

Call PHP’s password_hash() and store its output—not the submitted password. The resulting hash includes the algorithm and salt information needed for verification. PHP notes that PASSWORD_DEFAULT may change over time and recommends a database column that can grow beyond 60 bytes; 255 bytes is a reasonable choice.

When a user signs in

Retrieve the stored hash for the account and pass the submitted password and stored hash to password_verify(). PHP documents that this function is safe against timing attacks. If verification succeeds, use password_needs_rehash() to determine whether the valid password should be rehashed using the current parameters.

Do not compare plaintext passwords or try to recreate a salt yourself. Consult the PHP manual for the PHP version deployed, since password defaults and behavior can evolve.

Implement the login flow in this order

  1. Validate the submitted fields. Accept the expected login identifier and password, and handle missing or malformed input safely.
  2. Look up the account. Retrieve its stored password hash and trusted identity or permission data from the server-side account record.
  3. Verify the password. Use password_verify($submittedPassword, $storedHash). If verification fails, return a generic failure response that does not disclose whether the account exists.
  4. Establish the authenticated session safely. Set the account identity in the session only after successful verification, and regenerate the session identifier as appropriate to the application’s session lifecycle.
  5. Authorize the destination and every later request. A successful login proves identity; it does not automatically grant administrator permissions. Check access on the server before serving each restricted route or action.
  6. Redirect for convenience, not security. You may send an administrator and a regular user to different dashboards, but the authorization check must still protect each dashboard and its underlying actions.

This sequence describes the security decisions; it is not a complete form-handling implementation. The reviewed PHP guidance supports the password APIs and session protections, but does not prescribe one universal framework, database schema, or onboarding policy.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Protect every admin route and resource

Centralize the authorization check so protected endpoints apply consistent rules. Deny access unless the account’s trusted permissions allow the requested operation. Protect the underlying server-side action as well as the page that links to it: hiding an admin menu item does not secure its endpoint.

When a request targets a specific record, check that the account may act on that record. A guessed or changed identifier must not let a user read or modify another account’s data. This matters for both administrator-only functions and regular-user features such as viewing one’s own profile.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Harden sessions and state-changing requests

PHP’s session security configuration guidance documents cookie-only session IDs, strict mode, HttpOnly, Secure, and SameSite options. For a site that is served only over HTTPS, settings commonly considered include:

  • session.use_only_cookies=On
  • session.use_strict_mode=On
  • session.cookie_httponly=On
  • session.cookie_secure=On
  • session.cookie_samesite set to a value appropriate for the application

Confirm the available settings and their behavior for the PHP version and session handler actually in use. Do not set the Secure cookie option for a deployment that needs to serve the site over plain HTTP; use HTTPS for a production login site.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sessions do not prevent cross-site request forgery (CSRF). Do not use the session ID as a CSRF token. Use the framework’s CSRF protection when available, or implement a well-reviewed token-based defense and validate it on relevant state-changing requests. PHP explains this limitation in its session security documentation.

Common mistakes to avoid

  • Creating separate admin and user password systems when both account types can use the same secure authentication flow.
  • Trusting a role, account ID, or admin flag supplied by the browser.
  • Checking authorization only during login, only in a navigation menu, or only on the first page load.
  • Protecting a page but leaving its data-changing endpoint or resource lookup unprotected.
  • Storing plaintext passwords or using a custom password comparison instead of PHP’s password APIs.
  • Assuming that an authenticated session is also protected against CSRF.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.