PHPackages                             ninjaportal/portal-api - 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. [API Development](/categories/api)
4. /
5. ninjaportal/portal-api

ActiveLibrary[API Development](/categories/api)

ninjaportal/portal-api
======================

REST API package for NinjaPortal

0.1.1(2mo ago)001MITPHPPHP ^8.2

Since Feb 28Pushed 1mo agoCompare

[ Source](https://github.com/ninjaportal/portal-api)[ Packagist](https://packagist.org/packages/ninjaportal/portal-api)[ RSS](/packages/ninjaportal-portal-api/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (10)Versions (5)Used By (1)

NinjaPortal API Package
=======================

[](#ninjaportal-api-package)

REST API package for NinjaPortal (`ninjaportal/portal`) with:

- Versioned routes (`/api/v1/...`)
- Admin + consumer auth flows (JWT access token + DB refresh token)
- Admin RBAC (Spatie permissions)
- Consistent response envelope + API exception normalization
- Activity logging subscriber for Portal domain events

Routes
------

[](#routes)

- Default base path: `api/v1`
- Admin sub-prefix: `admin` (full admin base path: `api/v1/admin`)

Configuration Highlights
------------------------

[](#configuration-highlights)

Main config: `config/portal-api.php`

Important keys:

- `portal-api.prefix`
- `portal-api.admin_prefix`
- `portal-api.auth.consumer_model`
- `portal-api.auth.admin_model`
- `portal-api.auth.guards.*`
- `portal-api.rbac.enabled`
- `portal-api.authorization.use_policies`
- `portal-api.tokens.*`
- `portal-api.tokens.prune.*`

Out of the box, `portal-api` ships JWT-ready auth models:

- `NinjaPortal\Api\Models\User`
- `NinjaPortal\Api\Models\Admin`

When the shared `ninjaportal.models.User` / `ninjaportal.models.Admin` config values are still pointing at the core Portal models, `portal-api` promotes them to these API models automatically so the Portal repositories and API auth layer resolve the same classes. If your application already overrides those model config values, `portal-api`leaves them untouched.

Extensibility (Client Customization)
------------------------------------

[](#extensibility-client-customization)

### 1) Custom User/Admin Models

[](#1-custom-useradmin-models)

The package supports overriding the consumer/admin auth models via config:

- `PORTAL_API_CONSUMER_MODEL`
- `PORTAL_API_ADMIN_MODEL`

The API package now resolves model classes and table names through `NinjaPortal\Api\Support\PortalApiContext`, which is used by:

- auth flow (login)
- route-adjacent user resolution in admin user endpoints
- request validation rules that previously hardcoded `users` table

### 2) Authentication Plugins (MFA / SSO)

[](#2-authentication-plugins-mfa--sso)

Auth controllers now depend on `NinjaPortal\Api\Contracts\Auth\AuthFlowInterface` instead of directly implementing login logic.

Default implementation:

- `NinjaPortal\Api\Auth\AuthFlow`

Token lifecycle is abstracted by:

- `NinjaPortal\Api\Contracts\Auth\TokenServiceInterface`
- default: `NinjaPortal\Api\Services\TokenService`

This makes it easier for a separate package to:

- replace the auth flow (SSO-first login, MFA challenge flow)
- decorate token issuing/refresh/revoke behavior
- listen to auth lifecycle events

### 3) Auth Lifecycle Events (for plugins)

[](#3-auth-lifecycle-events-for-plugins)

Events emitted by the API package:

- `NinjaPortal\Api\Events\Auth\LoginAttemptedEvent`
- `NinjaPortal\Api\Events\Auth\LoginFailedEvent`
- `NinjaPortal\Api\Events\Auth\LoginSucceededEvent`
- `NinjaPortal\Api\Events\Auth\TokenIssuedEvent`
- `NinjaPortal\Api\Events\Auth\TokenRefreshedEvent`
- `NinjaPortal\Api\Events\Auth\TokenRevokedEvent`

Suggested MFA package approach:

1. Bind your own `AuthFlowInterface` implementation.
2. Reuse `TokenServiceInterface` after challenge success.
3. Optionally listen to auth events for auditing / throttling / risk scoring.

### 4) Authorization Strategy Replacement

[](#4-authorization-strategy-replacement)

Admin controllers can optionally perform policy checks through:

- `NinjaPortal\Api\Contracts\Authorization\ApiAuthorizerInterface`
- default implementation: `NinjaPortal\Api\Authorization\PolicyApiAuthorizer`

Disable policy checks (keep route RBAC only):

- `PORTAL_API_USE_POLICIES=false`

Replace the authorizer in another package/service provider if you need:

- ABAC
- tenant-aware checks
- external policy engines

RBAC vs Policy Checks
---------------------

[](#rbac-vs-policy-checks)

Two layers can coexist:

- Route RBAC (Spatie): controlled by `PORTAL_API_RBAC_ENABLED`
- Controller policy checks: controlled by `PORTAL_API_USE_POLICIES`

Recommended for standalone portal deployments:

- Keep both enabled (`true`)

Pagination / List Endpoint Conventions
--------------------------------------

[](#pagination--list-endpoint-conventions)

Shared helpers live in:

- `src/Http/Controllers/Controller.php`
- `src/Http/Mixins/ApiRequestMixin.php`

Preferred list pattern:

1. Use `listParams()` for `per_page`, `order_by`, `direction`
2. Query/paginate in service or query builder
3. Return via `respondPaginated()`

### Intentionally Unpaginated Endpoints (Current Design)

[](#intentionally-unpaginated-endpoints-current-design)

These are intentionally returned as full collections because they are typically small/config-like datasets:

- Admin settings index
- Admin menus index
- Admin menu items index (per menu)
- RBAC roles index
- RBAC permissions index

If a client deployment grows these significantly, convert them to the standard paginated pattern.

Refresh Token Pruning
---------------------

[](#refresh-token-pruning)

Refresh tokens are stored in `portal_api_refresh_tokens`.

Prune expired/revoked rows manually:

```
php artisan portal-api:tokens:prune
```

Queue prune job instead:

```
php artisan portal-api:tokens:prune --queue
```

Optional scheduler integration (package-level):

- `PORTAL_API_REFRESH_PRUNE_ENABLED=true`
- `PORTAL_API_REFRESH_PRUNE_QUEUE=false`
- `PORTAL_API_REFRESH_PRUNE_FREQUENCY=daily` (`daily` or `hourly`)
- `PORTAL_API_REFRESH_PRUNE_TIME=03:00` (used for `daily`)

Docs (Scribe)
-------------

[](#docs-scribe)

- Generate docs: `php artisan scribe:generate`
- Docs endpoint (if enabled in `config/scribe.php`): `/docs`

Development (Package-local)
---------------------------

[](#development-package-local)

Available scripts:

- `composer test`
- `composer analyse`
- `composer format`

Note:

- In this monorepo, package-local installs may need Composer path repositories for local package dependencies (`ninjaportal/portal`, etc.).

###  Health Score

37

—

LowBetter than 82% of packages

Maintenance95

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 77.8% 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 ~0 days

Total

2

Last Release

69d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/572472a15d795bd58c160445f6e9298cd82b756bf4355e860491785b5398d6f7?d=identicon)[Youssef20](/maintainers/Youssef20)

---

Top Contributors

[![lordjoo](https://avatars.githubusercontent.com/u/11289152?v=4)](https://github.com/lordjoo "lordjoo (7 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (2 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ninjaportal-portal-api/health.svg)

```
[![Health](https://phpackages.com/badges/ninjaportal-portal-api/health.svg)](https://phpackages.com/packages/ninjaportal-portal-api)
```

###  Alternatives

[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k2.9M88](/packages/bezhansalleh-filament-shield)[spatie/laravel-route-discovery

Auto register routes using PHP attributes

23645.0k2](/packages/spatie-laravel-route-discovery)[mll-lab/laravel-graphiql

Easily integrate GraphiQL into your Laravel project

683.2M9](/packages/mll-lab-laravel-graphiql)[simplestats-io/laravel-client

Client for SimpleStats!

4515.5k](/packages/simplestats-io-laravel-client)[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)[ryangjchandler/bearer

Minimalistic token-based authentication for Laravel API endpoints.

8129.8k](/packages/ryangjchandler-bearer)

PHPackages © 2026

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