Skip to content

Authentication

Moon ERP uses Laravel Sanctum for token-based API authentication. Every request to a protected endpoint must include a valid bearer token in the Authorization header.

How It Works

  1. The client sends credentials to the login or register endpoint.
  2. The server returns a plain-text Sanctum token.
  3. The client includes this token in the Authorization header for all subsequent requests.
  4. On logout, the token is revoked and can no longer be used.

Token Lifetime

Tokens do not expire by default. A token remains valid until the user explicitly logs out, which revokes it. You can store the token securely on the client and reuse it across sessions.

Authorization Header

All protected endpoints require the following header:

Authorization: Bearer {token}

Replace {token} with the value returned by login or register.

Endpoints

POST /api/auth/register

Create a new user account. This endpoint is public (no token required).

Request Body

FieldTypeRequiredDescription
company_idintegerYesID of the company to register under
namestringYesFull name (English)
name_arstringYesFull name (Arabic)
emailstringYesEmail address (unique per company)
passwordstringYesMinimum 8 characters
password_confirmationstringYesMust match password
phonestringNoPhone number
branch_idintegerNoID of the branch to assign
bash
curl -X POST https://moon-erp.test/api/auth/register \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "company_id": 1,
    "name": "Sara Ali",
    "name_ar": "سارة علي",
    "email": "sara@example.com",
    "password": "secret1234",
    "password_confirmation": "secret1234"
  }'
dart
import 'dart:convert';
import 'package:http/http.dart' as http;

final response = await http.post(
  Uri.parse('https://moon-erp.test/api/auth/register'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: jsonEncode({
    'company_id': 1,
    'name': 'Sara Ali',
    'name_ar': 'سارة علي',
    'email': 'sara@example.com',
    'password': 'secret1234',
    'password_confirmation': 'secret1234',
  }),
);

Response 201 Created

json
{
  "data": {
    "id": 2,
    "name": "سارة علي",
    "name_en": "Sara Ali",
    "name_ar": "سارة علي",
    "email": "sara@example.com",
    "phone": null,
    "locale": "ar",
    "is_active": true,
    "roles": ["employee"],
    "permissions": [],
    "created_at": "2026-02-16T12:00:00.000000Z",
    "updated_at": "2026-02-16T12:00:00.000000Z"
  },
  "token": "3|newtoken..."
}

POST /api/auth/login

Authenticate an existing user. This endpoint is public (no token required).

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address
passwordstringYesUser password
bash
curl -X POST https://moon-erp.test/api/auth/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "email": "sara@example.com",
    "password": "secret1234"
  }'
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/auth/login'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: jsonEncode({
    'email': 'sara@example.com',
    'password': 'secret1234',
  }),
);

final data = jsonDecode(response.body);
final token = data['token']; // Store this securely

Response 200 OK

json
{
  "data": {
    "id": 2,
    "name": "سارة علي",
    "name_en": "Sara Ali",
    "name_ar": "سارة علي",
    "email": "sara@example.com",
    "phone": null,
    "locale": "ar",
    "is_active": true,
    "company": { "id": 1, "name": "Moon Corp" },
    "branch": null,
    "roles": ["employee"],
    "permissions": [],
    "created_at": "2026-02-16T12:00:00.000000Z",
    "updated_at": "2026-02-16T12:00:00.000000Z"
  },
  "token": "4|logintoken..."
}

Error Response 401 Unauthorized

json
{
  "message": "Invalid credentials"
}

Error Response 403 Forbidden (inactive account)

json
{
  "message": "Account is inactive"
}

POST /api/auth/logout

Revoke the current access token. Requires authentication.

bash
curl -X POST https://moon-erp.test/api/auth/logout \
  -H "Accept: application/json" \
  -H "Authorization: Bearer 4|logintoken..."
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/auth/logout'),
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
);
// After logout, discard the stored token

Response 200 OK

json
{
  "message": "Logged out"
}

After logout, the token is permanently invalidated. The client must log in again to obtain a new token.


GET /api/auth/me

Retrieve the authenticated user's profile, including roles and permissions. Requires authentication.

bash
curl -X GET https://moon-erp.test/api/auth/me \
  -H "Accept: application/json" \
  -H "Authorization: Bearer 4|logintoken..."
dart
final response = await http.get(
  Uri.parse('https://moon-erp.test/api/auth/me'),
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
);

final profile = jsonDecode(response.body)['data'];

Response 200 OK

json
{
  "data": {
    "id": 2,
    "name": "سارة علي",
    "name_en": "Sara Ali",
    "name_ar": "سارة علي",
    "email": "sara@example.com",
    "phone": null,
    "locale": "ar",
    "is_active": true,
    "company": { "id": 1, "name": "Moon Corp" },
    "branch": null,
    "roles": ["employee"],
    "permissions": ["core.users.view", "core.settings.view"],
    "created_at": "2026-02-16T12:00:00.000000Z",
    "updated_at": "2026-02-16T12:00:00.000000Z"
  }
}

PUT /api/auth/me

Update the authenticated user's own profile. Requires authentication. All fields are optional -- only include the fields you want to change.

Request Body

FieldTypeRequiredDescription
namestringNoFull name (English)
name_arstringNoFull name (Arabic)
emailstringNoEmail address (unique per company)
phonestringNoPhone number
localestringNoPreferred locale (ar or en)
passwordstringNoNew password (min 8 characters)
password_confirmationstringNoRequired if password is provided
bash
curl -X PUT https://moon-erp.test/api/auth/me \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer 4|logintoken..." \
  -d '{
    "name": "Sara Ahmed Ali",
    "locale": "en"
  }'
dart
final response = await http.put(
  Uri.parse('https://moon-erp.test/api/auth/me'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
  body: jsonEncode({
    'name': 'Sara Ahmed Ali',
    'locale': 'en',
  }),
);

Response 200 OK

json
{
  "data": {
    "id": 2,
    "name": "Sara Ahmed Ali",
    "name_en": "Sara Ahmed Ali",
    "name_ar": "سارة علي",
    "email": "sara@example.com",
    "phone": null,
    "locale": "en",
    "is_active": true,
    "company": { "id": 1, "name": "Moon Corp" },
    "branch": null,
    "roles": ["employee"],
    "permissions": ["core.users.view", "core.settings.view"],
    "created_at": "2026-02-16T12:00:00.000000Z",
    "updated_at": "2026-02-16T14:00:00.000000Z"
  }
}

Security Recommendations

  • Store tokens in secure storage (Keychain on iOS, EncryptedSharedPreferences on Android, flutter_secure_storage in Flutter).
  • Never log tokens or include them in URLs.
  • Always use HTTPS in production.
  • Call the logout endpoint when the user signs out rather than just discarding the token locally.

Moon ERP API Documentation