Security — authentication and authorization

Who this is for

Pionia Shop already lists products. Now you need login and clear rules for who may create catalog rows or place orders. For attribute-only how-tos, start with Protecting actions. This page covers backends, secrets, and custom authentication classes.

What you will learn

  • What an authentication backend does
  • How to keep signing secrets out of git
  • When to use built-in JWT vs make:auth
  • How attributes and in-method checks fit together

Before you start

Before you start

Two moments in every request

  1. Identify — backends look at headers. The first match fills $this->auth() (usually JwtAuthentication).
  2. Authorize — attributes on the service/method decide if this action may run.
flowchart TD
  Req[HTTP request] --> Backends[Auth backends]
  Backends -->|recognized| User["$this->auth()"]
  Backends -->|unknown| Empty[no user]
  User --> Attr["#[Authenticated] / #[Can]"]
  Empty --> Attr
  Attr -->|no| Stop[401 or 403]
  Attr -->|yes| Action[Your action]

Secrets stay in .env

DoDon’t
Put JWT_SECRET in .envCommit production secrets
Use placeholders in tutorialsReturn password hashes in returnData
Rotate leaked valuesReuse sample keys from screenshots
php pionia shell
# secure_random_hex(32);

Usual path: JWT

[app_authentications]
jwt = "Pionia\Auth\JwtAuthentication"

Issue tokens in customer.login with jwt_encode(). Full guide: JWT authentication.

Custom backend

Sessions, partner API keys, or a proxy that already authenticated the user:

php pionia make:auth ApiKey

Return a ContextUserObject or null. Register under [app_authentications]. Order matters — first success wins.

After identify: authorize

#[Authenticated(except: ['login', 'register'])]
class CustomerService extends Service { /* … */ }

Ownership checks (“only cancel your own order”) stay inside the method with $this->auth(). Walkthrough: Protecting actions.

HelperMeaning
$this->auth()Current user context
$this->mustAuthenticate()Require login (401)
$this->can('…')One permission
$this->canAny / canAllAny / all permissions

Common mistakes

  • Backend class exists but missing from [app_authentications]
  • Locking login / register
  • Permission string typos → quiet 403s
  • Scaffolding a custom JWT class when JwtAuthentication already fits

What’s next

Protecting actions

Shop-focused attribute guide.

JWT authentication

customer.login tokens.

Security utilities

hash_password and more.