Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vendor
composer.lock
/.idea

180 changes: 180 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@

# Basic API Token Middleware for Laravel

This middleware provides a simple, secure token-based authentication mechanism for Laravel, designed for internal machine-to-machine communication (e.g., internal apps accessing other internal APIs) without the complexity of OAuth.

> ⚠️ **Security Note**: Always send API tokens via `Authorization: Bearer` headers. Do not use query parameters or POST body fields as they are insecure and unsupported.

---

## Installation

Install the package via Composer:

```bash
composer require uogsoe/basic-api-token-middleware
```

Publish the database migration and model:

```bash
php artisan vendor:publish
```

Select:`UoGSoE\ApiTokenMiddleware\ApiTokenServiceProvider`

Run the migration to create the `api_tokens` table:

```bash
php artisan migrate
```

---

## Usage

### Creating a Token

Generate a token for a service (e.g., `testservice`):

```bash
php artisan apitoken:create testservice
```

> The token will only be displayed once. Store it securely.

---

### Protecting Routes

In `routes/api.php`, apply the middleware:

```php
use Illuminate\Support\Facades\Route;

Route::middleware('apitoken:testservice')->group(function () {
Route::get('/hello', fn() => response()->json(['message' => 'Hello, World!']));
});
```

Multiple services:

```php
Route::middleware('apitoken:testservice,anotherservice')->group(function () {
Route::get('/hello', fn() => response()->json(['message' => 'Hello, World!']));
});
```

---

### Authenticating Requests

Send requests using the Authorization header:

```bash
curl -H "Authorization: Bearer jT7ryt28gi3YCvgE4WvluO1uVcb0ndVx" https://my-project.test/api/hello
```

**Successful Response:**

```json
HTTP/2 200
{"message": "Hello, World!"}
```

**Unauthorized Response:**

```json
HTTP/2 401
{"message":"Unauthorized"}
```

**Laravel Example:**

```php
use Illuminate\Support\Facades\Http;
Http::withHeaders([
'Authorization' => 'Bearer jT7ryt28gi3YCvgE4WvluO1uVcb0ndVx',
])->get('https://my-project.test/api/hello');
```

**AJAX Example:**

```javascript
fetch('https://my-project.test/api/hello', {
method: 'GET',
headers: {
'Authorization': 'Bearer jT7ryt28gi3YCvgE4WvluO1uVcb0ndVx',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```

> ❗ Avoid sending tokens via query strings or POST bodies - will result in a 401 Unauthorized response.

---

## Managing Tokens

- **List all tokens:**

```bash
php artisan apitoken:list
```

- **Regenerate a token:**

```bash
php artisan apitoken:regenerate testservice
```

- **Delete a token:**

```bash
php artisan apitoken:delete testservice
```

---

## Security Best Practices

- **Use HTTPS**: Encrypt all API traffic.
- **Secure Token Storage**: Use environment variables, secret vaults, or HTTP-only secure cookies. Avoid client-side exposure.
- **Token Expiry**: Use `apitoken:regenerate` periodically.
- **CORS Configuration** (in `config/cors.php`):

```php
'allowed_origins' => ['https://your-frontend.com'],
'supports_credentials' => true,
```

- **Rate Limiting**:

```php
Route::middleware('throttle:60,1')->get('/hello', fn() => response()->json(['message' => 'Hello, World!']));
```

- **XSS Protection**: Use Content Security Policy (CSP) and sanitize inputs.

---

## Upgrading from Previous Versions

If you were using `?api_token=` in URLs or POST bodies, **update clients** to use `Authorization: Bearer` headers immediately. These methods are no longer supported.

---

## Contributing

Contributions are welcome!
Submit PRs at: [https://github.com/uogsoe/basic-api-token-middleware](https://github.com/uogsoe/basic-api-token-middleware)
Ensure tests and security practices are followed.

---

## License

This project is licensed under the **MIT License**.
79 changes: 0 additions & 79 deletions Readme.md

This file was deleted.

15 changes: 7 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@
"email": "william.allan@glasgow.ac.uk"
}
],
"require": {},
"require-dev": {
"orchestra/testbench": "^10.0"
},
"autoload": {
"psr-4": {
"UoGSoE\\ApiTokenMiddleware\\": "src"
"UoGSoE\\ApiTokenMiddleware\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests",
"App\\": "src"
"Tests\\": "tests/"
}
},
"require": {},
"require-dev": {
"orchestra/testbench": "~3.0"
},
"extra": {
"laravel": {
"providers": [
"UoGSoE\\ApiTokenMiddleware\\ApiTokenServiceProvider"
]
}
}
}
}
2 changes: 1 addition & 1 deletion migrations/2018_04_18_090739_create_api_tokens_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class CreateApiTokensTable extends Migration
public function up()
{
Schema::create('api_tokens', function (Blueprint $table) {
$table->increments('id');
$table->id();
$table->string('service');
$table->string('token');
$table->timestamps();
Expand Down
31 changes: 22 additions & 9 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
stopOnFailure="false"
beStrictAboutTestsThatDoNotTestAnything="true">
<!-- Define test suites to run -->
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">

<!-- Configure code coverage reporting -->
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<directory suffix=".php">./vendor/uogsoe/apitokenmiddleware/src</directory>
</include>
<report>
<html outputDirectory="coverage"/>
<text outputFile="coverage.txt"/>
</report>
</coverage>

<!-- Set environment variables for testing -->
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="DB_CONNECTION" value="testing"/>
<env name="APP_KEY" value="base64:XZIR4ew4eM+kDTjst7Bitk3g6JGwrpaM+1MzfZ3xs1k="/>
<env name="APP_KEY" value="base64:XZIR4ew4eM+kDTjst7Bitk3g6JGwrpaM+1MzfZ3xs1k="/>
</php>
</phpunit>
</phpunit>
Loading