PHPackages                             artisan-build/built-for-cloud - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [DevOps &amp; Deployment](/categories/devops)
4. /
5. artisan-build/built-for-cloud

ActiveLibrary[DevOps &amp; Deployment](/categories/devops)

artisan-build/built-for-cloud
=============================

Shared building blocks for administering cloud-first Laravel apps from the Laravel Cloud CLI.

v0.2.0(3w ago)0388↓50%3MITPHPPHP ^8.3CI passing

Since Jun 15Pushed 3w agoCompare

[ Source](https://github.com/artisan-build/built-for-cloud)[ Packagist](https://packagist.org/packages/artisan-build/built-for-cloud)[ RSS](/packages/artisan-build-built-for-cloud/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (2)Dependencies (20)Versions (9)Used By (3)

Built for Cloud
===============

[](#built-for-cloud)

Shared building blocks for administering **cloud-first Laravel applications from the [Laravel Cloud](https://cloud.laravel.com) CLI** — no admin UI required.

These are the pieces that several Artisan Build apps (Matte, Hone, …) need in common: things you manage by running an Artisan command in your production environment and reading its output back on your machine. The package started with **API token management** and now also provides a shared **auth foundation** for apps that need an identical user/admin/invitation story.

> **Status:** the initial `0.x` release is being finalised. The package follows semantic versioning; pin to a version range you have tested.

Installation
------------

[](#installation)

```
composer require artisan-build/built-for-cloud
```

The service provider is auto-discovered. Publish the config if you want to tweak it:

```
php artisan vendor:publish --tag=built-for-cloud-config
```

API tokens
----------

[](#api-tokens)

Tokens are stored **hashed** in an `api_tokens` table (this package ships the migration). A token resolves only while it is unexpired; everything else about it — usage counts, rotation, revocation — is metadata around that one rule.

ConceptBehaviour**Resolution**A presented bearer token matches a row by `sha256` hash and resolves only when `expires_at` is `null` or in the future. That single check is the whole gate.**Rotation**Issues a new secret for the same logical token and lets the old one keep working for a **1‑hour grace window** (zero-downtime). `--emergency` kills the old secret immediately.**Revocation**Stops a token resolving immediately and records *why* (`revoked_at`) for the audit trail.**Usage**Each token tracks `last_used_at` and a request counter. Consuming apps can attribute their own records (e.g. jobs) to the resolving token.### The fallback token

[](#the-fallback-token)

A single plaintext **fallback token** can be read straight from the environment (`FALLBACK_TOKEN`). Any caller presenting it authenticates without a database row — handy for bootstrapping a fresh install or wiring up internal apps quickly.

It is deliberately low-ceremony and **not meant for production workloads**: delete it from the environment to disable it, and provision per-app database tokens instead. When `FALLBACK_TOKEN` is absent, fallback authentication is off entirely.

Administering from the Cloud CLI
--------------------------------

[](#administering-from-the-cloud-cli)

Token administration is designed to be driven from your machine against your deployed environment. Each command resolves the target environment by asking Cloud for the application's environment list (using a single one automatically, prompting when there is more than one), then runs the work in production via the Cloud CLI and brings the output back to you.

Secrets never leave your machine: a new token's plaintext is generated locally and shown once — only its hash is sent to production, so plaintext never lands in retained command output.

```
php artisan token:create       # issue a new per-app token (plaintext shown once)
php artisan token:rotate        # rotate, with a 1h grace window (--emergency to cut over now)
php artisan token:revoke        # revoke immediately
php artisan token:list                # list tokens and their status
php artisan token:usage []      # show usage for a token (or all)

```

Auth foundation
---------------

[](#auth-foundation)

Built for Cloud augments your Laravel app's existing user model. It does **not** create or own a `users` table. Instead, it reads the configured model from `config('auth.providers.users.model')`(falling back to `App\Models\User`) and adds reusable admin and invitation building blocks around it.

### User admin flag

[](#user-admin-flag)

The package ships a guarded migration that runs late and adds `is_admin boolean default false` to an existing `users` table. It never creates or replaces your app's user table, so run your app's users table migration first and let the package migration run after that. If the users table does not exist yet, the package migration is a no-op.

Make sure your app's user model casts the column as a boolean. Keep `is_admin` out of `$fillable` as defense-in-depth so user-submitted form data cannot mass-assign privileges:

```
protected $fillable = ['name', 'email', 'password'];

protected function casts(): array
{
    return ['is_admin' => 'boolean'];
}
```

### Create the first admin

[](#create-the-first-admin)

Use the shared command to create an administrator in the configured user model:

```
php artisan create-admin --email=admin@example.com --password=secret --name="Admin"
```

If any admin already exists, the command refuses to create another one. Pass `--force` when you intentionally want multiple admins:

```
php artisan create-admin --email=ops@example.com --password=secret --name="Ops" --force
```

When an option is omitted, the command prompts for it using Laravel Prompts.

The command requires the `is_admin` column to exist and fails with a migration reminder when it is missing. It sets the admin flag with `forceFill()`, so your app should not make `is_admin` fillable.

### Invitations

[](#invitations)

The package provides an `ArtisanBuild\BuiltForCloud\Invitation` model and migration. Consuming apps build their own routes, controllers, notifications, and views around these library methods:

```
use ArtisanBuild\BuiltForCloud\Invitation;

$invitation = Invitation::invite('new@user.test');

$user = Invitation::accept($invitation->token, [
    'name' => 'New User',
    'password' => 'plain-password',
]);
```

`invite()` generates a unique token and defaults `expires_at` to seven days from now. `accept()` only accepts pending, unexpired invitations; it creates the configured user with the invitation email, hashes a provided `password`, marks `accepted_at`, and returns the new user. `accept()` never grants admin access: privileged incoming attributes such as `is_admin` are ignored and the created user is forced non-admin when the column exists. Invalid, expired, or already accepted tokens throw `ArtisanBuild\BuiltForCloud\Exceptions\InvalidInvitation`.

Useful scopes are available for app UI and housekeeping:

```
Invitation::pending()->get();
Invitation::accepted()->get();
Invitation::expired()->delete();
```

### Middleware aliases

[](#middleware-aliases)

The service provider registers route middleware aliases:

AliasBehaviour`bfc.auth`Requires an authenticated user. JSON requests receive `401`; browser requests redirect to a `login` route when one exists, otherwise `401`.`bfc.admin`Requires an authenticated user whose `is_admin` attribute is truthy; otherwise `403`.Use them in the consuming app's routes:

```
Route::middleware('bfc.auth')->group(function () {
    // signed-in users
});

Route::middleware('bfc.admin')->group(function () {
    // administrators only
});
```

Installer scaffold
------------------

[](#installer-scaffold)

Client packages can share the same `*:install` command plumbing with `ArtisanBuild\BuiltForCloud\Commands\Concerns\WritesInstallEnv`. The trait keeps installer commands focused on prompts and option parsing while it handles the repeatable side effects:

HelperBehaviour`setEnvironmentValue()`Purely returns `.env` contents with a key appended or replaced idempotently. Values with spaces or special characters are quoted.`writeEnvFile()`Reads an env file, applies key/value updates, writes only when the contents changed, and creates the file when missing.`pinComposerConstraint()`Sets `require[vendor/package]` to a clean caret major such as `^2` in `composer.json`, creating `require` when needed.`summarize()`Prints a tidy install summary from the consuming Artisan command.Prompts stay in the consuming command, so each app can ask the right questions while sharing the file and composer mutation logic:

```
use ArtisanBuild\BuiltForCloud\Commands\Concerns\WritesInstallEnv;
use Illuminate\Console\Command;

final class SinkInstallCommand extends Command
{
    use WritesInstallEnv;

    protected $signature = 'sink:install {--api-url=}';

    public function handle(): int
    {
        $apiUrl = $this->option('api-url') ?: text('Sink API URL');

        $envChanged = $this->writeEnvFile($this->laravel->environmentFilePath(), [
            'SINK_API_URL' => $apiUrl,
        ]);

        $this->pinComposerConstraint(base_path('composer.json'), 'artisan-build/sink', 1);

        $this->summarize([
            'env changed' => $envChanged,
            'composer package' => 'artisan-build/sink:^1',
        ]);

        return self::SUCCESS;
    }
}
```

A cloud-provisioning installer command is planned for a future v2 release; this scaffold only covers local install command helpers.

Contributing
------------

[](#contributing)

This package is developed by [Artisan Build](https://artisan.build). Issues and pull requests are welcome.

License
-------

[](#license)

MIT © Artisan Build. See [LICENSE](LICENSE).

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance95

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

6

Last Release

23d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1053395?v=4)[Ed Grosvenor](/maintainers/edgrosvenor)[@edgrosvenor](https://github.com/edgrosvenor)

---

Top Contributors

[![edgrosvenor](https://avatars.githubusercontent.com/u/1053395?v=4)](https://github.com/edgrosvenor "edgrosvenor (6 commits)")

---

Tags

laravelapi-tokensArtisan Buildlaravel cloud

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/artisan-build-built-for-cloud/health.svg)

```
[![Health](https://phpackages.com/badges/artisan-build-built-for-cloud/health.svg)](https://phpackages.com/packages/artisan-build-built-for-cloud)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M348](/packages/psalm-plugin-laravel)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M139](/packages/laravel-pulse)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M134](/packages/roots-acorn)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k30.2M151](/packages/laravel-cashier)[laravel/ai

The official AI SDK for Laravel.

1.0k3.2M256](/packages/laravel-ai)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

78622.3M192](/packages/laravel-mcp)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
