Skip to content
Merged
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
279 changes: 17 additions & 262 deletions packages/auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,289 +3,50 @@
> [!IMPORTANT]
> This repository is a read-only mirror of the [utopia-php monorepo](https://github.com/utopia-php/monorepo). Development happens in [`packages/auth`](https://github.com/utopia-php/monorepo/tree/main/packages/auth) — please open issues and pull requests there.

[![Build Status](https://travis-ci.org/utopia-php/auth.svg?branch=master)](https://travis-ci.org/utopia-php/auth)
![Total Downloads](https://img.shields.io/packagist/dt/utopia-php/auth.svg)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord)](https://appwrite.io/discord)

Utopia Auth library is a simple and lite library for handling authentication and authorization in PHP applications. This library provides a collection of secure hashing algorithms and authentication proofs for building robust authentication systems. This library is maintained by the [Appwrite team](https://appwrite.io).
Utopia Auth is a simple, dependency-free PHP library for building authentication and authorization: secure password hashing, authentication proofs (tokens, codes, phrases), and signing/verifying OAuth2 and OpenID Connect JWTs. It is maintained by the [Appwrite team](https://appwrite.io).

Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project it is dependency free and can be used as standalone with any other PHP project or framework.
Although it is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used standalone with any PHP project or framework.

## Getting Started

Install using composer:

```bash
composer require utopia-php/auth
```

## System Requirements

Utopia Framework requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.

## Features

### Supported Hashing Hashes

- **Argon2** - Modern, secure, and recommended password hashing algorithm
- **Bcrypt** - Well-established and secure password hashing
- **Scrypt** - Memory-hard password hashing algorithm
- **ScryptModified** - Modified version of Scrypt with additional features
- **SHA** - Various SHA hash implementations
- **PHPass** - Portable password hashing framework
- **MD5** (Not recommended for passwords, legacy support only)

### Token Issuers

A generic framework for minting signed [JWS](https://datatracker.ietf.org/doc/html/rfc7515) tokens. The base `Issuer` is **not** tied to any particular protocol — it owns the JWS mechanics (header assembly, `jti` generation, base64url encoding and the header/payload/signature structure) and delegates only the signing algorithm and claim set to a subclass.

## Usage

### Data Store

```php
<?php

use Utopia\Auth\Store;

// Create a new store
$store = new Store();

// Set various types of data
$store->set('userId', '12345')
->set('name', 'John Doe')
->set('isActive', true)
->set('preferences', ['theme' => 'dark', 'notifications' => true]);

// Get values with optional defaults
$userId = $store->get('userId');
$missing = $store->get('missing', 'default value');

// Encode store data to a base64 string
$encoded = $store->encode();

// Later, decode the string back into a store
$newStore = new Store();
$newStore->decode($encoded);

// Access the decoded data
echo $newStore->get('name'); // Outputs: John Doe
```

### Password Hashing

```php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use Utopia\Auth\Proofs\Password;
use Utopia\Auth\Hashes\Argon2;
use Utopia\Auth\Hashes\Bcrypt;

// Initialize password authentication with default algorithms
$password = new Password();

// Hash a password (uses Argon2 by default)
$hash = $password->hash('user-password');

// Verify the password
$isValid = $password->verify('user-password', $hash);

// Use a specific algorithm with custom parameters
$bcrypt = new Bcrypt();
$bcrypt->setCost(12); // Increase cost factor for better security

$password->setHash($bcrypt);
$hash = $password->hash('user-password');
```

### Authentication Tokens

```php
<?php

use Utopia\Auth\Proofs\Token;

// Generate secure authentication tokens
$token = new Token(32); // 32 characters length
$authToken = $token->generate(); // Random token
$hashedToken = $token->hash($authToken); // Store this in database

// Later, verify the token
$isValid = $token->verify($authToken, $hashedToken);
```

### One-Time Codes

```php
<?php

use Utopia\Auth\Proofs\Code;

// Generate verification codes (e.g., for 2FA)
$code = new Code(6); // 6-digit code
$verificationCode = $code->generate();
$hashedCode = $code->hash($verificationCode);

// Verify the code
$isValid = $code->verify($verificationCode, $hashedCode);
```

### Human-Readable Phrases

```php
<?php

use Utopia\Auth\Proofs\Phrase;

// Generate memorable authentication phrases
$phrase = new Phrase();
$authPhrase = $phrase->generate(); // e.g., "Brave cat"
$hashedPhrase = $phrase->hash($authPhrase);

// Verify the phrase
$isValid = $phrase->verify($authPhrase, $hashedPhrase);
```

### Advanced Hash Configuration

```php
<?php

use Utopia\Auth\Hashes\Scrypt;
use Utopia\Auth\Hashes\Argon2;

// Configure Scrypt parameters
$scrypt = new Scrypt();
$scrypt
->setCpuCost(16) // CPU/Memory cost parameter
->setMemoryCost(14) // Memory cost parameter
->setParallelCost(2) // Parallelization parameter
->setLength(64) // Output length in bytes
->setSalt('randomsalt123'); // Custom salt

// Configure Argon2 parameters
$argon2 = new Argon2();
$argon2
->setMemoryCost(65536) // Memory cost in KiB
->setTimeCost(4) // Number of iterations
->setThreads(3); // Number of threads
```

### Issuing Tokens

#### OAuth2 Access Tokens (RFC 9068)

```php
<?php

use Utopia\Auth\Issuers\Asymmetric\AccessToken;

// Generate an RSA key pair (do this once and persist the keys)
[$privateKey, $publicKey] = AccessToken::generateKeyPair();

$accessToken = new AccessToken(
$privateKey,
$publicKey,
'https://example.com/v1/oauth2/my-app' // The "iss" claim (authorization server)
);

// Issue a signed RS256 access token
$jwt = $accessToken->issue(
subject: 'user-123', // "sub" — the resource owner
audience: ['https://api.example.com'], // "aud" — the resource server
clientId: 'client-abc', // "client_id" — the client it was issued to
authTime: time(), // "auth_time" — when the user authenticated
duration: 3600, // Lifetime in seconds ("exp")
scopes: ['openid', 'profile', 'email']
);

$jwt = $accessToken->issue(
subject: 'user-123',
audience: ['https://api.example.com', 'https://mcp.example.com'],
clientId: 'client-abc',
authTime: time(),
duration: 3600,
scopes: ['openid', 'profile']
);

// Publish the public key as a JWK so resource servers can verify tokens
$jwk = $accessToken->getPublicJwk();
$keyId = $accessToken->getKeyId();
```

#### OAuth2 Refresh Tokens (HS256)

```php
<?php

use Utopia\Auth\Issuers\Symmetric\RefreshToken;

// Generate a signing secret (do this once and keep it server-side)
$secret = RefreshToken::generateSecret();

$refreshToken = new RefreshToken(
$secret,
'https://example.com/v1/oauth2/my-app'
);

// Issue a signed HS256 refresh token
$jwt = $refreshToken->issue(
subject: 'user-123', // "sub"
audience: 'https://example.com/v1/oauth2/token', // "aud" — the token endpoint
clientId: 'client-abc', // "client_id"
duration: 1209600, // Lifetime in seconds (e.g. 14 days)
scopes: ['openid', 'profile']
);
```

#### ID Tokens (OpenID Connect)

```php
<?php

use Utopia\Auth\Issuers\Asymmetric\IdToken;

[$privateKey, $publicKey] = IdToken::generateKeyPair();

$idToken = new IdToken(
$privateKey,
$publicKey,
'https://example.com/v1/oauth2/my-app'
);

// Issue a signed OIDC id_token
$jwt = $idToken->issue(
subject: 'user-123', // "sub" — the authenticated user
audience: 'client-abc', // "aud" — the client the token is for
authTime: time(), // "auth_time"
duration: 3600, // Lifetime in seconds ("exp")
nonce: 'n-0S6_WzA2Mj', // Optional "nonce" from the auth request
accessToken: $jwt, // Optional co-issued access_token (adds "at_hash")
code: null // Optional co-issued authorization code (adds "c_hash")
);
```

> Both asymmetric and symmetric issuers accept an optional `keyId` constructor argument (the JWS `kid` header) for key rotation. For asymmetric issuers it is derived deterministically from the public key when omitted.
## System Requirements

#### OAuth2 Resource Indicators (RFC 8707)
Utopia Auth requires PHP 8.1 or later. We recommend using the latest PHP version whenever possible.

```php
<?php
## Features

use Utopia\Auth\OAuth2\ResourceIndicators;
- **Password hashing** — Argon2, Bcrypt, Scrypt (and a modified Scrypt), SHA, PHPass, and MD5 (legacy only)
- **Authentication proofs** — cryptographically random tokens, one-time codes (e.g. 2FA), and human-readable phrases
- **Data store** — a base64-encodable key/value envelope for serializing authentication state
- **Token issuers** — mint signed [JWS](https://datatracker.ietf.org/doc/html/rfc7515): OAuth2 access tokens (RFC 9068), refresh tokens, and OpenID Connect id_tokens
- **Token verifiers** — verify RS256/HS256 JWS with an `alg`-confusion guard and standard claim checks
- **OAuth2 helpers** — RFC 8707 resource indicators

$resources = ResourceIndicators::from([
'https://api.example.com/',
'https://mcp.example.com/',
]);
$previouslyGrantedResources = ResourceIndicators::from(['https://api.example.com/']);
## Documentation

$isAllowed = $resources->isSubsetOf($previouslyGrantedResources);
$unchanged = $resources->equals($previouslyGrantedResources);
$audience = $resources->audience('https://cloud.example.com/v1/project');
$serialized = $resources->toArray();
```
- [Password Hashing](docs/hashing.md) — algorithms and tuning
- [Authentication Proofs](docs/proofs.md) — tokens, one-time codes, and phrases
- [Data Store](docs/store.md) — encode/decode authentication state
- [JSON Web Tokens](docs/jwt.md) — issuing and verifying OAuth2 / OpenID Connect tokens

## Tests

Expand All @@ -295,12 +56,6 @@ To run all unit tests, use the following Docker command:
docker compose exec tests vendor/bin/phpunit --configuration phpunit.xml tests
```

To run static code analysis, use the following command:

```bash
docker compose exec tests composer check
```

## Security

We take security seriously. If you discover any security-related issues, please email security@appwrite.io instead of using the issue tracker.
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"test": "phpunit --configuration phpunit.xml"
},
"require": {
"php": ">=8.0",
"php": ">=8.1",
"ext-hash": "*",
"ext-openssl": "*",
"ext-scrypt": "*",
Expand Down
4 changes: 2 additions & 2 deletions packages/auth/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading