In Laravel Passport 13, what kind of client does each passport:client flag create, and why does a --password client fail until enablePasswordGrant() is called?
answer
- no flag means authorization code
- --client, --device, --personal, --public
- UUID id, secret shown once
- grant_types column binds the client
- password grant off since Passport 12
basics
~20 sNo flag creates an authorization-code client; --client a client-credentials client, --device a device-flow client, --personal the personal access client, --password and --implicit legacy clients, --public one without a secret. The password grant itself is only registered after Passport::enablePasswordGrant().
solid answer
~40 s`passport:client` writes a row to `oauth_clients` with a UUID id, a hashed secret and a `grant_types` list that binds what the client may do. With no flag it creates an **authorization code** client (plus refresh token), asks for redirect URIs and optionally adds the device flow. `--client` creates a **client credentials** client, `--device` a device-authorization client, `--personal` the personal access client for a user provider, `--implicit` an implicit client and `--password` a password client. `--public` omits the secret, for PKCE apps that cannot keep one. The plain secret is printed once, because only its hash is stored. `--password` only creates the client: since Passport 12 the authorization server registers the password grant only after `Passport::enablePasswordGrant()` in `boot()`, so until then `/oauth/token` rejects `grant_type=password`. The implicit grant is likewise off until `enableImplicitGrant()`.
code
bash · 8 lines# marketplace integrator acting for shippers (authorization code)
php artisan passport:client --name="Freight Marketplace" --redirect_uri=https://market.example.test/callback
# carrier's nightly rate sync (no user involved)
php artisan passport:client --client --name="Carrier Rate Sync"
# handheld scanners in the warehouse
php artisan passport:client --device --name="Dock Scanners"go deeper
Match the common flags to their grants: no flag for authorization code, --client for machine clients, --personal for createToken, --public for apps without a secret.
Explain grant_types on the client row, hashed secrets shown once, and why enablePasswordGrant() is a separate server-side switch.
Refuse the password grant for integrators with a documented alternative, and plan secret regeneration and client revocation as operations.
Set the onboarding policy: which grants your platform offers third parties at all, and how clients are approved and retired.
## What a client is In Passport an **OAuth2 client** is an application registered with your authorization server. It lives in `oauth_clients` with a **UUID** primary key (Passport 13's default), a name, a `secret` (hashed, nullable), optional `redirect_uris`, an optional `provider`, a `grant_types` list and a `revoked` flag. The `grant_types` list matters: the authorization server asks each client whether it supports the grant being used, so a client-credentials client cannot suddenly run an authorization-code flow. ## The flags | Command | Grant types stored | Typical integrator on a logistics platform | |---|---|---| | `passport:client` | `authorization_code`, `refresh_token` (+ device code if you say yes) | a shipping marketplace acting for shippers | | `passport:client --public` | same, no secret | a desktop or mobile tool using PKCE | | `passport:client --client` | `client_credentials` | a carrier's nightly rate sync | | `passport:client --device` | device code, `refresh_token` | a warehouse handheld with no keyboard | | `passport:client --personal` | `personal_access` | backs `$user->createToken()` | | `passport:client --password` | `password`, `refresh_token` | legacy first-party apps only | | `passport:client --implicit` | `implicit` | legacy; not recommended | Other options: `--name=` (defaults to prompting with `APP_NAME`), `--redirect_uri=` (comma-separated list), `--provider=` for the user provider on personal and password clients. After creation the command prints the **Client ID** and, for confidential clients, the **Client Secret** with a warning that it will not be shown again. Passport 13 always hashes client secrets; an app upgraded from older versions runs `passport:hash` once to hash existing plain-text secrets. ## Why `--password` is not enough Creating a client and enabling a grant are two different switches: 1. `passport:client --password` only writes a row whose `grant_types` includes `password`. 2. The **authorization server** decides which grants exist. Passport's service provider always enables authorization code, refresh token and client credentials, enables device code when its routes are registered, and enables **password** only when `Passport::$passwordGrantEnabled` is true — set by `Passport::enablePasswordGrant()`. 3. Since **Passport 12** that flag defaults to `false`. Without it, `POST /oauth/token` with `grant_type=password` is rejected as an unsupported grant, whatever clients exist. The same pattern applies to `enableImplicitGrant()`. The device authorization grant is the opposite: on by default, switched off by setting `Passport::$deviceCodeGrantEnabled` to `false`. ## Why the docs discourage turning it on Passport's documentation says it no longer recommends password grant tokens and points to the grants the OAuth2 server currently recommends. For a first-party mobile app, authorization code with PKCE (a `--public` client) is the documented alternative; for a first-party app that needs no OAuth at all, Sanctum is simpler. ## Revoking and rotating - A client's `revoked` flag disables it: `findActive()` ignores revoked clients, so the client can no longer obtain tokens and the `passport` guard stops authenticating its existing ones. - `ClientRepository::regenerateSecret()` issues a new secret; the old one stops working at once, so coordinate with the integrator. ## Clients for users, not just for admins `passport:client` suits clients you register yourself. When integrators register their own apps through your developer portal, the docs point to `ClientRepository` methods such as `createAuthorizationCodeGrantClient($name, $redirectUris, $confidential, $user)`, which stores the owning user in the `owner` morph columns; `$user->oauthApps()` then lists that user's clients. Build the portal's forms on these methods rather than inserting `oauth_clients` rows by hand, so secrets are hashed and `grant_types` are set consistently. ## Interview checklist 1. Name the default: no flag means authorization code with refresh tokens. 2. Map `--client`, `--device`, `--personal` and `--public` to their use. 3. Say that creating a client does not enable a grant, and that the password and implicit grants stay off until you enable them. 4. Mention UUID IDs and hashed secrets as the Passport 13 defaults.
- What does --public change for an authorization-code client?It stores no secret, so the client is public: it cannot authenticate at the token endpoint with a secret and must use PKCE. Use it for mobile, desktop and single-page apps whose code ships to users and therefore cannot keep a secret.
- An integrator lost its client secret. Can you read it from oauth_clients?No. Passport 13 stores only a hash of the secret, and the plain value exists only in the command output or the model's `plainSecret` right after creation. Regenerate the secret and hand the new one over through a secure channel; the old one stops working.
saying these in an interview costs you the question
- passport:client --password makes the password grant work on its own
- The password grant is enabled by default in Passport 13
- Client secrets can be read back from the oauth_clients table
- Any client can use any grant once it has an ID and secret
- A public client is safe to use without PKCE