PHPackages                             hackthebox/laravel-iam-auth - 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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. hackthebox/laravel-iam-auth

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

hackthebox/laravel-iam-auth
===========================

AWS IAM authentication for Laravel: RDS database connections and SDK credential caching for PHP-FPM

v3.0.0(1mo ago)21.5k[1 issues](https://github.com/hackthebox/laravel-iam-auth/issues)[1 PRs](https://github.com/hackthebox/laravel-iam-auth/pulls)MITPHPPHP ^8.2CI passing

Since Mar 6Pushed 1mo agoCompare

[ Source](https://github.com/hackthebox/laravel-iam-auth)[ Packagist](https://packagist.org/packages/hackthebox/laravel-iam-auth)[ RSS](/packages/hackthebox-laravel-iam-auth/feed)WikiDiscussions main Synced yesterday

READMEChangelog (8)Dependencies (24)Versions (24)Used By (0)

Laravel IAM Auth
================

[](#laravel-iam-auth)

AWS IAM authentication for Laravel: RDS database connections and SDK credential caching. Designed for EKS workloads using Pod Identity or IRSA (no sidecars, no static credentials).

Features
--------

[](#features)

- **RDS IAM Auth** — overrides Laravel's MySQL, MariaDB, and PostgreSQL connectors to generate short-lived IAM auth tokens via the AWS SDK when `use_iam_auth` is enabled on a connection.
- **AWS Credential Caching** — caches resolved AWS SDK credentials across PHP-FPM requests (APCu-first), benefiting all AWS SDK calls (S3, SQS, SES, etc.).

How It Works
------------

[](#how-it-works)

This package overrides Laravel's database connectors for MySQL, MariaDB, and PostgreSQL. When `use_iam_auth` is enabled on a connection, the connector generates a short-lived IAM auth token (via the AWS SDK) and uses it as the database password. The token is generated fresh on each connection; the AWS SDK credential resolution that backs the token signature is cached across PHP-FPM requests (APCu-first).

The package does **not** introduce a new database driver. Laravel's `MySqlConnection`, `MariaDbConnection`, and `PostgresConnection` are used as-is.

The package wires `config('aws.credentials')` to a custom `CachedCredentialProvider` so that the AWS SDK singleton (`app('aws')`) and any client created from it share cached credentials across PHP-FPM requests. Other-package customizations on the SDK singleton are preserved (the singleton is not rebuilt).

Driver Support
--------------

[](#driver-support)

Supports MySQL, MariaDB, and PostgreSQL. All three drivers share the same connector trait (`InjectsIamToken`), so the auth-token signing, cache-defense, and auth-rejection-detection behavior is identical across them.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.2
- Laravel 12 or 13
- aws/aws-sdk-php-laravel &gt;= 3.7 and aws/aws-sdk-php &gt;= 3.249 (both installed automatically)
- APCu extension (recommended for production — caches resolved AWS credentials across FPM requests)
- RDS instance with IAM authentication enabled
- SSL CA bundle (bundled — override via `IAM_AUTH_SSL_CA_PATH` env if needed)

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

[](#installation)

```
composer require hackthebox/laravel-iam-auth
```

The service provider is auto-discovered. To publish the config:

```
php artisan vendor:publish --tag=iam-auth-config
```

Configuration
-------------

[](#configuration)

### Database Connection

[](#database-connection)

Add `use_iam_auth` and `region` to your connection in `config/database.php`:

**MySQL / MariaDB:**

```
'mysql' => [
    'driver' => 'mysql', // or 'mariadb'
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'use_iam_auth' => env('DB_USE_IAM_AUTH', false),
    'region' => env('AWS_DEFAULT_REGION', 'eu-central-1'),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],
```

**PostgreSQL:**

```
'pgsql' => [
    'driver' => 'pgsql',
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '5432'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'use_iam_auth' => env('DB_USE_IAM_AUTH', false),
    'region' => env('AWS_DEFAULT_REGION', 'eu-central-1'),
    'charset' => 'utf8',
    'prefix' => '',
    'schema' => 'public',
],
```

When `use_iam_auth` is `false`, the connector behaves identically to Laravel's default — `password` is used as-is.

### Environment Variables

[](#environment-variables)

**Production (EKS with Pod Identity):**

```
DB_USE_IAM_AUTH=true
DB_PASSWORD=
AWS_DEFAULT_REGION=eu-central-1
```

**Local development:**

```
DB_USE_IAM_AUTH=false
DB_PASSWORD=secret
```

### Package Config

[](#package-config)

The package config (`config/iam-auth.php`):

KeyDefaultDescription`region``AWS_DEFAULT_REGION` / `AWS_REGION` envFallback region when not set on connection`credential_provider``default`AWS credential provider for all SDK operations (S3, SQS, RDS, etc.). Override with `IAM_AUTH_CREDENTIAL_PROVIDER` env. Supported: `default`, `environment`, `ecs`, `web_identity`, `instance_profile`, `sso`, `ini`.`cache_store``null`Laravel cache store for caching resolved AWS credentials when APCu is unavailable. Use `file`, `redis`, `memcached`, etc. **Never** `database` or `dynamodb`. Override with `IAM_AUTH_CACHE_STORE` env.`debug``false`When `true`, emits a verbose `iam-auth.token-access` debug log on every `getToken` call, including `host`, `port`, `username`, `region`, `force_fresh`, and `access_key_prefix` (first 8 characters of the AccessKeyId). High log volume; intended for short investigation soaks only. Override with `IAM_AUTH_DEBUG` env.`pgsql_sslmode``verify-full`SSL mode for PostgreSQL IAM connections. Override with `IAM_AUTH_PGSQL_SSLMODE` env.`ssl_ca_path`Bundled `global-bundle.pem`Path to the RDS CA bundle. Override with `IAM_AUTH_SSL_CA_PATH` env.RDS IAM Database User Setup
---------------------------

[](#rds-iam-database-user-setup)

### MySQL / MariaDB

[](#mysql--mariadb)

```
CREATE USER 'app_user' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';
GRANT ALL ON mydb.* TO 'app_user'@'%';
```

### PostgreSQL

[](#postgresql)

```
CREATE USER app_user WITH LOGIN;
GRANT rds_iam TO app_user;
```

EKS Pod Identity Setup
----------------------

[](#eks-pod-identity-setup)

1. Install the Pod Identity Agent addon
2. Create an IAM role with a trust policy for `pods.eks.amazonaws.com`
3. Attach an IAM policy allowing `rds-db:connect`
4. Create a pod identity association for your namespace/service account
5. Restart your pods

The AWS SDK default credential chain picks up Pod Identity credentials automatically. No code changes needed beyond enabling `use_iam_auth`.

*The option to force a specific credential provider exists via the `credential_provider` config option.*

Token Generation
----------------

[](#token-generation)

IAM auth tokens are valid for 15 minutes and are generated fresh on each database connection. Because RDS token signing is local HMAC work using already-cached credentials, the cost per connection is negligible.

**Bundled CA certificate:** The package includes the AWS RDS global CA bundle. This certificate bundle may become stale over time. If you encounter SSL verification errors, download the latest bundle from AWS and set `IAM_AUTH_SSL_CA_PATH` to point to it.

Defensive Behavior
------------------

[](#defensive-behavior)

**Expired-on-arrival credentials throw.** When the AWS SDK credential provider hands back a `Credentials` object that is already past its expiration, `CachedCredentialProvider` emits a `Log::warning` under the channel `iam-auth.credentials-expired-on-arrival` and throws a `RuntimeException` before the credentials reach the SigV4 signer. The same guard also lives in `AwsCredentialCacheStore::set()` as defense-in-depth against any external code writing expired credentials directly into the cache.

**Cache-backend resilience.** All three cache operations (`get`, `set`, `remove`) treat Laravel cache backend failures as best-effort: transient errors (e.g. Redis temporarily unavailable) are swallowed and logged under `iam-auth.cache-store-write-failed`, so a single backend blip cannot fail user requests even when credentials were resolved successfully. Misconfiguration (an unsafe `cache_store` like `database` or `dynamodb`) still throws loudly via `assertSafeCacheStore` before any operation.

**Auth rejection triggers a single retry with fresh credentials.** Any auth rejection from RDS that reaches the connector (SQLSTATE class `28` for PostgreSQL, native code `1045` for MySQL/MariaDB) triggers the following recovery sequence:

1. Log `iam-auth.rds-auth-rejected` (warning) with the current credential cache snapshot.
2. Invalidate `CachedCredentialProvider`'s in-process memo and the cross-request store.
3. Re-sign the RDS token against freshly resolved credentials, which also repopulates the store so sibling workers benefit from the rotation.
4. Retry the connection once.

If the retry also fails with an auth rejection, `iam-auth.rds-auth-rejected-retry-failed` is logged and the exception is re-thrown. This covers the common case of a credential rotation window landing between the credential cache write and the DB connect.

The credential snapshot in the warning reflects the cache state at the moment the warning fires. On a busy multi-worker pod a concurrent refresh between signing and rejection can produce a snapshot of post-rotation credentials; this is cosmetic and does not affect the retry logic.

**Performance note.** If you disable credential caching (no APCu, no `cache_store`), every DB connection will re-invoke the SDK credential chain. Keep credential caching enabled for IAM-auth workloads.

Debugging
---------

[](#debugging)

Set `IAM_AUTH_DEBUG=true` in your environment to enable verbose per-`getToken` logging. The package emits an `iam-auth.token-access` debug line on every call:

- `host`, `port`, `username`, `region`: connection target.
- `force_fresh`: whether the call bypassed the credential cache (i.e., this is a retry after auth rejection).
- `access_key_prefix`: first 8 characters of the AccessKeyId used to sign the token (never the full credential).

The `iam-auth.rds-auth-rejected` and `iam-auth.rds-auth-rejected-retry-failed` warnings are unconditional and fire regardless of `IAM_AUTH_DEBUG`.

This log volume is too high for steady-state production. Enable for short investigation soaks only. No credential secrets are ever logged.

AWS Credential Caching
----------------------

[](#aws-credential-caching)

When using IAM roles (IRSA, Pod Identity, instance profiles), the AWS SDK resolves credentials via network calls to STS or IMDS on every PHP-FPM request. Under high traffic this adds latency and can hit rate limits.

This package caches resolved AWS SDK credentials across requests, benefiting **all** AWS SDK calls made by your application (S3, SQS, SES, etc.), not just RDS token generation.

The `cache_store` setting controls AWS credential caching. APCu is always preferred when available.

**Proactive refresh window.** `CachedCredentialProvider` refreshes credentials 60 seconds before their reported expiration to avoid handing the SigV4 signer credentials that may expire mid-request. The constant (`CachedCredentialProvider::REFRESH_WINDOW = 60`) matches the AWS SDK's own `CredentialProvider::memoize()` default. This window is not configurable in v3; the load impact is bounded (one extra fetch per credentials cycle, where the cycle is hours long for STS sessions).

**Important:** Credential caching only applies to AWS clients created through the SDK singleton (e.g. `app('aws')->createS3()`). Clients instantiated directly (`new S3Client([...])`) bypass the singleton and do not benefit from cached credentials. Always resolve clients via the container:

```
// Correct: uses cached credentials
$s3 = app('aws')->createS3();

// Bypasses credential caching
$s3 = new \Aws\S3\S3Client([...]);
```

**Cache security note:** Cached AWS credentials are stored in plaintext in the configured backend. Ensure your cache backend is appropriately secured. APCu stores credentials in shared memory within the PHP process, which is not accessible externally.

**Laravel 13 `serializable_classes`:** Laravel 13 added a `cache.serializable_classes` config option, defaulted to `false` in fresh installs, which restricts the classes the cache may unserialize (defense against deserialization gadget chains). The `cache_store` fallback path stores an `Aws\Credentials\Credentials` object, so on Laravel 13 apps that keep the `false` default the credential entry is read back as `__PHP_Incomplete_Class` and treated as a cache miss. The effect is silent degradation of the fallback path (every request re-resolves credentials), not an error. If you rely on the `cache_store` fallback rather than APCu, allow-list the class:

```
// config/cache.php
'serializable_classes' => [
    Aws\Credentials\Credentials::class,
],
```

The APCu path is unaffected (APCu uses its own serialization, not the Laravel cache repository).

**Static credentials are not cached.** Credentials without a reported expiration (e.g. static env keys, `~/.aws/credentials` profiles without an `expiration`) cannot be safely cached because the package has no signal for when to evict them. Each request will re-invoke the SDK credential chain. This is intentional: the expired-on-arrival guard in `AwsCredentialCacheStore::set()` prevents storing credentials the SDK has already marked expired, but long-lived credentials have no expiration to check. Production workloads on IRSA / Pod Identity / instance profiles get full caching benefits because the SDK reports an expiration.

Known upstream limitations
--------------------------

[](#known-upstream-limitations)

This package consciously does not work around the following AWS-side gaps. Each limitation is documented so consumers understand the behavior and where to file issues upstream if material.

### EKS Pod Identity Agent may serve credentials AWS has invalidated

[](#eks-pod-identity-agent-may-serve-credentials-aws-has-invalidated)

The agent's internal cache can lag behind server-side session revocation. No client-side mechanism can detect this. The connector retry helps only if the agent has rotated between attempts. If your observability shows sustained `iam-auth.rds-auth-rejected-retry-failed` events, file with `aws/containers-roadmap`; do not add client-side mitigation here.

### AWS SDK retry middleware does not see RDS IAM auth errors

[](#aws-sdk-retry-middleware-does-not-see-rds-iam-auth-errors)

RDS speaks the database wire protocol, so auth rejections arrive as `PDOException`, never as AWS SDK exceptions. The SDK's credential-refresh retry cannot apply. The connector-layer retry in `InjectsIamToken` is the correct place for the equivalent recovery logic.

Migrating from v2 to v3
-----------------------

[](#migrating-from-v2-to-v3)

If you are on v1, follow the v1 → v2 migration notes in the [v2.x branch README](https://github.com/hackthebox/laravel-iam-auth/blob/main-v2/README.md) first, then return here.

v3 is a breaking change from v2 with the following migration steps:

1. Update `composer.json` to require `^3.0`.
2. Remove `cache_ttl` and `credentials_expiry_buffer` from any `config/iam-auth.php` overrides. The RDS token cache is gone (tokens are signed per call); credential cache expiry is governed by the AWS SDK's standard `Aws\CacheInterface` contract.
3. Remove the `IAM_AUTH_CACHE_TTL` and `IAM_AUTH_CREDENTIALS_EXPIRY_BUFFER` env vars from deployment manifests.
4. Existing APCu/Laravel cache entries from v2 will be discarded automatically (different cache key, different value shape). No migration step required.
5. Custom handlers or middleware on the `aws` SDK singleton now actually survive (v3 no longer rebuilds the singleton).

After deployment, expect occasional `iam-auth.rds-auth-rejected` warnings (followed by silent successful retries) during credential rotation windows. Sustained `iam-auth.rds-auth-rejected-retry-failed` events indicate the residual case and should be escalated upstream.

License
-------

[](#license)

MIT

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance83

Actively maintained with recent releases

Popularity24

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.1% 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 ~6 days

Recently: every ~12 days

Total

20

Last Release

33d ago

Major Versions

v1.1.0 → v2.0.02026-03-26

v2.0.1 → v3.0.0-rc.12026-05-19

v2.0.2 → v3.0.0-rc.82026-05-21

2.x-dev → v3.0.0-rc.92026-06-19

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/8687447?v=4)[makelarisjr](/maintainers/makelarisjr)[@makelarisjr](https://github.com/makelarisjr)

![](https://avatars.githubusercontent.com/u/13113025?v=4)[Dimosthenis Schizas](/maintainers/dimoschi)[@dimoschi](https://github.com/dimoschi)

---

Top Contributors

[![dimoschi](https://avatars.githubusercontent.com/u/13113025?v=4)](https://github.com/dimoschi "dimoschi (100 commits)")[![vlasopoulos](https://avatars.githubusercontent.com/u/1096466?v=4)](https://github.com/vlasopoulos "vlasopoulos (3 commits)")

---

Tags

laravelawsAuthenticationiamrdsekspod-identitycredential-caching

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/hackthebox-laravel-iam-auth/health.svg)

```
[![Health](https://phpackages.com/badges/hackthebox-laravel-iam-auth/health.svg)](https://phpackages.com/packages/hackthebox-laravel-iam-auth)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M293](/packages/laravel-ai)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45844.8k1](/packages/pressbooks-pressbooks)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[ellaisys/aws-cognito

Laravel Authentication using AWS Cognito (Web and API)

121269.8k1](/packages/ellaisys-aws-cognito)[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6796.8k7](/packages/hasinhayder-tyro)

PHPackages © 2026

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