Laravel package for Connex DCB login: server-side auth-login + protected-script, browser-only dcbprotect / gateway-load, server-side login-connex + login-confirm-connex, customizable login UI, mobile Sanctum tokens.
Package migrations add Connex subscriber fields from OTP confirm success:
| Column | Example | Source |
|---|---|---|
msisdn |
218920920110 |
success.msisdn |
subscriber |
exist |
success.subscriber |
status |
active |
success.status |
operator |
Libyana |
success.operator |
expiration_date |
2032-08-11 15:56:54 |
success.expiration_date |
php artisan migrateMigrations live in packages/torgodly/connex/database/migrations/ (auto-loaded by the package).
Ensure your User model includes these in $fillable (and expiration_date cast as datetime).
From the Laravel app root:
php artisan testCovers URL building, upstream HTTP (faked), user sync, OTP confirm API, Sanctum token issuance, and the login page.
- PHP 8.2+
- Laravel 10, 11, 12, or 13
- laravel/sanctum (recommended for mobile API tokens after OTP confirm)
Submit https://github.com/NeaMatrix/connex-package on Packagist.org, then:
composer require neamatrix/connex:^1.1
php artisan vendor:publish --tag=connex-config
php artisan migrate
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrateIf you see "Could not find a version matching minimum-stability (stable)", use the GitHub repo directly:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/NeaMatrix/connex-package.git"
}
]composer require neamatrix/connex:^1.1Or allow dev stability once:
composer require neamatrix/connex:dev-main"repositories": [
{
"type": "path",
"url": "packages/torgodly/connex",
"options": { "symlink": true }
}
],
"require": {
"neamatrix/connex": "@dev"
}Each call uses CONNEX_BASE_URL + CONNEX_*_ENDPOINT.
| Purpose | Env | Default |
|---|---|---|
| Auth token | CONNEX_AUTH_LOGIN_ENDPOINT |
/auth-login |
| DCB script | CONNEX_PROTECTED_SCRIPT_ENDPOINT |
/protected-script |
| Send OTP | CONNEX_LOGIN_CONNEX_ENDPOINT |
/login-connex |
| Confirm OTP | CONNEX_LOGIN_CONFIRM_ENDPOINT |
/login-confirm-connex |
CONNEX_BASE_URL=https://jobassistant.mooo.com
CONNEX_AUTH_LOGIN_ENDPOINT=/auth-login
CONNEX_PROTECTED_SCRIPT_ENDPOINT=/protected-script
CONNEX_LOGIN_CONNEX_ENDPOINT=/login-connex
CONNEX_LOGIN_CONFIRM_ENDPOINT=/login-confirm-connexCONNEX_AUTH_EMAIL=your@api.user
CONNEX_AUTH_PASSWORD=secret
CONNEX_WEB_LOGIN_PATH=/connex/login
CONNEX_DEBUG_LOG=true
CONNEX_SUBMIT_BUTTON_ID=cta_button| Step | Where it runs |
|---|---|
auth-login, protected-script, login-connex |
Laravel (POST /connex/api/bootstrap, POST /connex/api/request-otp) |
dcbprotect script + DCBProtectRun + gateway-load |
Browser (antifraud; credentials never sent to the client) |
login-confirm-connex |
Laravel (POST /connex/api/confirm-otp) |
ConnexLoginConfig exposes only Laravel API URLs + CSRF + selectors — not CONNEX_AUTH_EMAIL, CONNEX_AUTH_PASSWORD, or upstream URLs.
Package registers GET {CONNEX_WEB_LOGIN_PATH} (default /connex/login) → connex::login.
All layout and CSS live in your view — not in config/connex.php. The package only requires correct element IDs (from connex.selectors) and the submit button outside the hidden phone/OTP step wrappers.
Publish the example and edit it:
php artisan vendor:publish --tag=connex-viewsCopy resources/views/vendor/connex/login.blade.php to e.g. resources/views/my-login.blade.php, change classes/markup freely, then:
CONNEX_LOGIN_VIEW=my-loginMinimal custom page:
<!DOCTYPE html>
<html>
<head><title>My login</title></head>
<body class="my-page">
<x-connex-login class="my-login-root" data-connex-hidden-class="is-hidden">
@include('connex::partials.hidden-fields')
<div id="connex_phone_step" class="my-phone-step">
<input id="msisdn" name="msisdn" type="tel" class="my-input" required>
</div>
<div id="connex_otp_step" class="is-hidden my-otp-step">
<p id="connex_otp_hint" class="my-hint">Check your SMS</p>
<input id="otp" name="otp" type="text" class="my-input" inputmode="numeric">
</div>
<button
id="cta_button"
type="button"
disabled
class="my-btn my-btn--disabled"
data-connex-label-sign-in="Continue"
data-connex-label-loading="Please wait…"
data-connex-label-verify-otp="Verify"
data-connex-enabled-class="my-btn my-btn--primary"
data-connex-disabled-class="my-btn my-btn--disabled"
>Please wait…</button>
</x-connex-login>
</body>
</html>data-connex-hidden-classon<x-connex-login>must match the class you use to hide steps (e.g. Tailwindhidden, Bootstrapd-none, or your ownis-hidden).- Button
data-connex-enabled-class/data-connex-disabled-classare optional; JS swaps them when enabling/disabling the button.
Without the component — same markup, end with:
@include('connex::partials.hidden-fields')
@include('connex::partials.scripts')Wrap markup in <div data-connex-login-root data-connex-hidden-class="hidden"> so step toggling works.
Required elements (configurable via config/connex.php → selectors):
| Purpose | Default id / name |
|---|---|
| MSISDN input | #msisdn |
| Submit button | #cta_button — must stay outside hidden phone/otp step wrappers (default layout does this) |
| Transaction | #transaction_identify |
| Device type | name="device_type" value web |
- Page load →
POST /connex/api/bootstrap(freshtransaction_identify+dcbprotect). - User submits phone →
POST /connex/api/request-otp(server callslogin-connex; OTP sent). - UI automatically switches to the OTP field (
#otpin#connex_otp_step; button label becomes “Verify OTP”). - User submits OTP →
POST /connex/api/confirm-otp(Laravel):- Calls upstream
login-confirm-connexwithmsisdn+otp+device_type - Creates/updates local user from Connex
successpayload - Issues Sanctum token for the mobile app
- Runs your
HandlesOtpConfirmationhandler for custom JSON
- Calls upstream
Implement Torgodly\Connex\Contracts\HandlesOtpConfirmation and bind it:
$this->app->bind(HandlesOtpConfirmation::class, YourHandler::class);public function handle(Authenticatable $user, array $connexSuccess): array
{
// Return extra keys merged into the API response (redirect URLs, app flags, etc.)
return ['app' => ['tier' => 'premium']];
}{
"messageCode": "00",
"success": { "message": "OTP confirmed", "connex": { "msisdn": "218...", "status": "active", ... } },
"auth": {
"token": "1|plainTextToken...",
"token_type": "Bearer",
"expires_at": null,
"user": { "id": 1, "msisdn": "218...", "status": "active", "operator": "Libyana", "expiration_date": "..." }
},
"app": { }
}Mobile app: store auth.token, send Authorization: Bearer {token} on API calls.
document.addEventListener('connex:authenticated', function (e) {
console.log(e.detail.auth.token);
});- UI: design only in Blade views —
<x-connex-login>is a thin wrapper; removedconnex.ui.classesconfig and styled partials.
- Fix: OTP confirm updates existing users matched by
msisdnor{msisdn}@connex.localemail (no duplicate email error).
- Security: upstream auth, protected-script, and login-connex run on the server; browser only runs
dcbprotect/gateway-load. - New API routes:
POST {CONNEX_API_PREFIX}/bootstrap,POST …/request-otp. - Default confirm upstream path:
/login-confirm-connex(CONNEX_LOGIN_CONFIRM_ENDPOINT).
- Send
device_typeon login-confirm upstream request.
- Fix: Sign In button visible on OTP step.
- Initial release.