diff --git a/docs/customization/integrating_custom_view_libs.md b/docs/customization/integrating_custom_view_libs.md index fc97891bb..4025de85c 100644 --- a/docs/customization/integrating_custom_view_libs.md +++ b/docs/customization/integrating_custom_view_libs.md @@ -1,6 +1,8 @@ # Integrating Custom View Libraries -If your application uses a different method to convert view files to HTML than CodeIgniter's built-in `view()` helper you can easily integrate your system anywhere that a view is rendered within Shield. All controllers and actions use the `CodeIgniter\Shield\Traits\Viewable` trait which provides a simple `view()` method that takes the same arguments as the `view()` helper. This allows you to extend the Action or Controller and only change the single method of rendering the view, leaving all of the logic untouched so your app will not need to maintain Shield logic when it doesn't need to change it. +If your application uses a different method to convert view files to HTML than CodeIgniter's built-in `view()` helper, you can easily integrate your system anywhere that a view is rendered within Shield. + +All controllers and actions use the `CodeIgniter\Shield\Traits\Viewable` trait which provides a simple `view()` method that takes the same arguments as the `view()` helper. This allows you to extend the Action or Controller and only change the single method of rendering the view, leaving all of the logic untouched so your app will not need to maintain Shield logic when it doesn't need to change it. ```php use Acme\Themes\Traits\Themeable; diff --git a/docs/customization/route_config.md b/docs/customization/route_config.md index 729383280..01f59c412 100644 --- a/docs/customization/route_config.md +++ b/docs/customization/route_config.md @@ -1,4 +1,4 @@ -# Customizing Route Configuration +# Customizing Routes If you need to customize how any of the auth features are handled, you will likely need to update the routes to point to the correct controllers. You can still use the `service('auth')->routes()` helper, but you will need to pass the `except` option with a list of routes to customize: diff --git a/docs/customization/table_names.md b/docs/customization/table_names.md index 2fcaad8c7..03eca1c98 100644 --- a/docs/customization/table_names.md +++ b/docs/customization/table_names.md @@ -17,4 +17,5 @@ public array $tables = [ Set the table names that you want in the array values. -> **Note** You must change the table names before running database migrations. +> **Note** +> You must change the table names before running database migrations. diff --git a/docs/customization/user_provider.md b/docs/customization/user_provider.md index 36af8d838..12246043c 100644 --- a/docs/customization/user_provider.md +++ b/docs/customization/user_provider.md @@ -1,7 +1,7 @@ # Customizing User Provider If you want to customize user attributes, you need to create your own -[User Provider](../concepts.md#user-providers) class. +[User Provider](../getting_started/concepts.md#user-providers) class. The only requirement is that your new class MUST extend the provided `CodeIgniter\Shield\Models\UserModel`. Shield has a CLI command to quickly create a custom `UserModel` class by running the following diff --git a/docs/customization/validation_rules.md b/docs/customization/validation_rules.md index f0442ff72..f637d4301 100644 --- a/docs/customization/validation_rules.md +++ b/docs/customization/validation_rules.md @@ -36,7 +36,8 @@ Shield has the following rules for registration: ]; ``` -> **Note** If you customize the table names, the table names +> **Note** +> If you customize the table names, the table names > (`users` and `auth_identities`) in the above rules will be automatically > changed. The rules are implemented in > `RegisterController::getValidationRules()`. @@ -78,7 +79,8 @@ If you need a different set of rules for registration, you can specify them in y ]; ``` -> **Note** If you customize the table names, set the correct table names in the +> **Note** +> If you customize the table names, set the correct table names in the > rules. ## Login diff --git a/docs/getting_started/authenticators.md b/docs/getting_started/authenticators.md new file mode 100644 index 000000000..0714ea226 --- /dev/null +++ b/docs/getting_started/authenticators.md @@ -0,0 +1,16 @@ +# Authenticators + +## Authenticator List + +Shield provides the following Authenticators: + +- **Session** authenticator provides traditional ID/Password authentication. + It uses username/email/password to authenticate against and stores the user + information in the session. See [Using Session Authenticator](../quick_start_guide/using_session_auth.md) for usage. +- **AccessTokens** authenticator provides stateless authentication using Personal + Access Tokens passed in the HTTP headers. + See [Protecting an API with Access Tokens](../guides/api_tokens.md) for usage. +- **HmacSha256** authenticator provides stateless authentication using HMAC Keys. + See [Protecting an API with HMAC Keys](../guides/api_hmac_keys.md) for usage. +- **JWT** authenticator provides stateless authentication using JSON Web Token. To use this, + you need additional setup. See [JWT Authentication](../addons/jwt.md). diff --git a/docs/concepts.md b/docs/getting_started/concepts.md similarity index 98% rename from docs/concepts.md rename to docs/getting_started/concepts.md index c5f6c3f65..58d4641c9 100644 --- a/docs/concepts.md +++ b/docs/getting_started/concepts.md @@ -21,7 +21,7 @@ on the standard Config class if nothing is found in the database. Shield has a model to handle user persistence. Shield calls this the "User Provider" class. A default model is provided for you by the `CodeIgniter\Shield\Models\UserModel` class. -You can use your own model to customize user attributes. See [Customizing User Provider](./customization/user_provider.md) for details. +You can use your own model to customize user attributes. See [Customizing User Provider](../customization/user_provider.md) for details. ## User Identities diff --git a/docs/getting_started/configuration.md b/docs/getting_started/configuration.md new file mode 100644 index 000000000..44694bb97 --- /dev/null +++ b/docs/getting_started/configuration.md @@ -0,0 +1,27 @@ +# Configuration + +## Config files + +Shield has a lot of Config items. Change the default values as needed. + +If you have completed the setup according to this documentation, you will have +the following configuration files: + +- **app/Config/Auth.php** +- **app/Config/AuthGroups.php** - For Authorization +- **app/Config/AuthToken.php** - For AccessTokens and HmacSha256 Authentication +- **app/Config/AuthJWT.php** - For JWT Authentication + +Note that you do not need to have configuration files for features you do not use. + +This section describes the major Config items that are not described elsewhere. + +## AccessTokens Authenticator + +### Access Token Lifetime + +By default, Access Tokens can be used for 1 year since the last use. This can be easily modified in the **app/Config/Auth.php** config file. + +```php +public int $unusedTokenLifetime = YEAR; +``` diff --git a/docs/getting_started/install.md b/docs/getting_started/install.md new file mode 100644 index 000000000..8a23656b0 --- /dev/null +++ b/docs/getting_started/install.md @@ -0,0 +1,182 @@ +# Installation + +These instructions assume that you have already [installed the CodeIgniter 4 app starter](https://codeigniter.com/user_guide/installation/installing_composer.html) as the basis for your new project, set up your **.env** file, and created a database that you can access via the Spark CLI script. + +## Requirements + +- [Composer](https://getcomposer.org) +- Codeigniter **v4.2.7** or later +- A created database that you can access via the Spark CLI script + - InnoDB (not MyISAM) is required if MySQL is used. + +## Composer Installation + +Installation is done through [Composer](https://getcomposer.org). The example assumes you have it installed globally. +If you have it installed as a phar, or otherwise you will need to adjust the way you call composer itself. + +```console +composer require codeigniter4/shield +``` + +### Troubleshooting + +#### IMPORTANT: composer error + +If you get the following error: + +```console +Could not find a version of package codeigniter4/shield matching your minimum-stability (stable). +Require it with an explicit version constraint allowing its desired stability. +``` + +1. Run the following commands to change your [minimum-stability](https://getcomposer.org/doc/articles/versions.md#minimum-stability) in your project `composer.json`: + + ```console + composer config minimum-stability dev + composer config prefer-stable true + ``` + +2. Or specify an explicit version: + + ```console + composer require codeigniter4/shield:dev-develop + ``` + + The above specifies `develop` branch. + See + + ```console + composer require codeigniter4/shield:^1.0.0-beta + ``` + + The above specifies `v1.0.0-beta` or later and before `v2.0.0`. + See + +## Initial Setup + +### Command Setup + +1. Run the following command. This command handles steps 1-5 of *Manual Setup* and runs the migrations. + + ```console + php spark shield:setup + ``` + + > **Note** + > If you want to customize table names, you must change the table names + > before running database migrations. + > See [Customizing Table Names](../customization/table_names.md). + +2. Configure **app/Config/Email.php** to allow Shield to send emails with the [Email Class](https://codeigniter.com/user_guide/libraries/email.html). + + ```php + helpers = array_merge($this->helpers, ['setting']); + + // Do Not Edit This Line + parent::initController($request, $response, $logger); + } + ``` + + This requires that all of your controllers extend the `BaseController`, but that's a good practice anyway. + +3. **Routes Setup** The default auth routes can be setup with a single call in **app/Config/Routes.php**: + + ```php + service('auth')->routes($routes); + ``` + +4. **Security Setup** Set `Config\Security::$csrfProtection` to `'session'` (or set `security.csrfProtection = session` in your **.env** file) for security reasons, if you use Session Authenticator. + +5. **Migration** Run the migrations. + + > **Note** + > If you want to customize table names, you must change the table names + > before running database migrations. + > See [Customizing Table Names](../customization/table_names.md). + + ```console + php spark migrate --all + ``` + + #### Note: migration error + + When you run `spark migrate --all`, if you get `Class "SQLite3" not found` error: + + 1. Remove sample migration files in **tests/_support/Database/Migrations/** + 2. Or install `sqlite3` php extension + +6. Configure **app/Config/Email.php** to allow Shield to send emails. + + ```php + **Note** By default, `$authenticatorHeader['tokens']` is set to `Authorization`. You can change this value by setting the `$authenticatorHeader['tokens']` value in the **app/Config/Auth.php** config file. +> **Note** +> By default, `$authenticatorHeader['tokens']` is set to `Authorization`. You can change this value by setting the `$authenticatorHeader['tokens']` value in the **app/Config/Auth.php** config file. Tokens are issued with the `generateAccessToken()` method on the user. This returns a `CodeIgniter\Shield\Entities\AccessToken` instance. Tokens are hashed using a SHA-256 algorithm before being saved to the database. The access token returned when you generate it will include a `raw_token` field that contains the plain-text, un-hashed, token. You should display this to your user at once so they have a chance to copy it somewhere safe, as this is the only time this will be available. After this request, there is no way to get the raw token. diff --git a/docs/index.md b/docs/index.md index 81a746ebc..ee28fc5a8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,14 +16,33 @@ The primary goals for Shield are: ### Important Features -* Session-based authentication (traditional email/password with remember me) +* Session-based authentication (traditional ID/Password with Remember-me) * Stateless authentication using Personal Access Tokens * Optional Email verification on account registration * Optional Email-based Two-Factor Authentication after login -* Magic Login Links when a user forgets their password -* Flexible groups-based access control (think roles, but more flexible) -* Users can be granted additional permissions +* Magic Link Login when a user forgets their password +* Flexible Groups-based access control (think Roles, but more flexible) +* Users can be granted additional Permissions ### License Shield is licensed under the MIT License - see the [LICENSE](https://github.com/codeigniter4/shield/blob/develop/LICENSE) file for details. + +### Acknowledgements + +Every open-source project depends on it's contributors to be a success. The following users have +contributed in one manner or another in making Shield: + + + Contributors + + +Made with [contrib.rocks](https://contrib.rocks). + +The following articles/sites have been fundamental in shaping the security and best practices used +within this library, in no particular order: + +- [Google Cloud: 13 best practices for user account, authentication, and password management, 2021 edition](https://cloud.google.com/blog/products/identity-security/account-authentication-and-password-management-best-practices) +- [NIST Digital Identity Guidelines](https://pages.nist.gov/800-63-3/sp800-63b.html) +- [Implementing Secure User Authentication in PHP Applications with Long-Term Persistence (Login with "Remember Me" Cookies) ](https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence) +- [Password Storage - OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) diff --git a/docs/install.md b/docs/install.md deleted file mode 100644 index 47aad61b0..000000000 --- a/docs/install.md +++ /dev/null @@ -1,283 +0,0 @@ -# Installation - -These instructions assume that you have already [installed the CodeIgniter 4 app starter](https://codeigniter.com/user_guide/installation/installing_composer.html) as the basis for your new project, set up your **.env** file, and created a database that you can access via the Spark CLI script. - -## Requirements - -- [Composer](https://getcomposer.org) -- Codeigniter **v4.2.7** or later -- A created database that you can access via the Spark CLI script - -## Composer Installation - -Installation is done through [Composer](https://getcomposer.org). The example assumes you have it installed globally. -If you have it installed as a phar, or otherwise you will need to adjust the way you call composer itself. - -```console -composer require codeigniter4/shield -``` - -### Troubleshooting - -#### IMPORTANT: composer error - -If you get the following error: - -```console -Could not find a version of package codeigniter4/shield matching your minimum-stability (stable). -Require it with an explicit version constraint allowing its desired stability. -``` - -1. Run the following commands to change your [minimum-stability](https://getcomposer.org/doc/articles/versions.md#minimum-stability) in your project `composer.json`: - - ```console - composer config minimum-stability dev - composer config prefer-stable true - ``` - -2. Or specify an explicit version: - - ```console - composer require codeigniter4/shield:dev-develop - ``` - - The above specifies `develop` branch. - See - - ```console - composer require codeigniter4/shield:^1.0.0-beta - ``` - - The above specifies `v1.0.0-beta` or later and before `v2.0.0`. - See - -## Initial Setup - -### Command Setup - -1. Run the following command. This command handles steps 1-5 of *Manual Setup* and runs the migrations. - - ```console - php spark shield:setup - ``` - - > **Note** If you want to customize table names, you must change the table names - > before running database migrations. - > See [Customizing Table Names](./customization/table_names.md). - -2. Configure **app/Config/Email.php** to allow Shield to send emails with the [Email Class](https://codeigniter.com/user_guide/libraries/email.html). - - ```php - helpers = array_merge($this->helpers, ['setting']); - - // Do Not Edit This Line - parent::initController($request, $response, $logger); - } - ``` - - This requires that all of your controllers extend the `BaseController`, but that's a good practice anyway. - -3. **Routes Setup** The default auth routes can be setup with a single call in **app/Config/Routes.php**: - - ```php - service('auth')->routes($routes); - ``` - -4. **Security Setup** Set `Config\Security::$csrfProtection` to `'session'` (or set `security.csrfProtection = session` in your **.env** file) for security reasons, if you use Session Authenticator. - -5. **Migration** Run the migrations. - - > **Note** If you want to customize table names, you must change the table names - > before running database migrations. - > See [Customizing Table Names](./customization/table_names.md). - - ```console - php spark migrate --all - ``` - - #### Note: migration error - - When you run `spark migrate --all`, if you get `Class "SQLite3" not found` error: - - 1. Remove sample migration files in **tests/_support/Database/Migrations/** - 2. Or install `sqlite3` php extension - - If you get `Specified key was too long` error: - - 1. Use InnoDB, not MyISAM. - -6. Configure **app/Config/Email.php** to allow Shield to send emails. - - ```php - \CodeIgniter\Shield\Filters\SessionAuth::class, - 'tokens' => \CodeIgniter\Shield\Filters\TokenAuth::class, - 'hmac' => \CodeIgniter\Shield\Filters\HmacAuth::class, - 'chain' => \CodeIgniter\Shield\Filters\ChainAuth::class, - 'auth-rates' => \CodeIgniter\Shield\Filters\AuthRates::class, - 'group' => \CodeIgniter\Shield\Filters\GroupFilter::class, - 'permission' => \CodeIgniter\Shield\Filters\PermissionFilter::class, - 'force-reset' => \CodeIgniter\Shield\Filters\ForcePasswordResetFilter::class, - 'jwt' => \CodeIgniter\Shield\Filters\JWTAuth::class, -]; -``` - -| Filters | Description | -|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| session and tokens | The `Session` and `AccessTokens` authenticators, respectively. | -| chained | The filter will check both authenticators in sequence to see if the user is logged in through either of authenticators, allowing a single API endpoint to work for both an SPA using session auth, and a mobile app using access tokens. | -| jwt | The `JWT` authenticator. See [JWT Authentication](./addons/jwt.md). | -| hmac | The `HMAC` authenticator. See [HMAC Authentication](./guides/api_hmac_keys.md). | -| auth-rates | Provides a good basis for rate limiting of auth-related routes. | -| group | Checks if the user is in one of the groups passed in. | -| permission | Checks if the user has the passed permissions. | -| force-reset | Checks if the user requires a password reset. | - -These can be used in any of the [normal filter config settings](https://codeigniter.com/user_guide/incoming/filters.html#globals), or [within the routes file](https://codeigniter.com/user_guide/incoming/routing.html#applying-filters). - -> **Note** These filters are already loaded for you by the registrar class located at **src/Config/Registrar.php**. - -### Protect All Pages - -If you want to limit all routes (e.g. `localhost:8080/admin`, `localhost:8080/panel` and ...), you need to add the following code in the **app/Config/Filters.php** file. - -```php -public $globals = [ - 'before' => [ - // ... - 'session' => ['except' => ['login*', 'register', 'auth/a/*']], - ], - // ... -]; -``` - -### Rate Limiting - -To help protect your authentication forms from being spammed by bots, it is recommended that you use -the `auth-rates` filter on all of your authentication routes. This can be done with the following -filter setup: - -```php -public $filters = [ - 'auth-rates' => [ - 'before' => [ - 'login*', 'register', 'auth/*' - ] - ] -]; -``` - -### Forcing Password Reset - -If your application requires a force password reset functionality, ensure that you exclude the auth pages and the actual password reset page from the `before` global. This will ensure that your users do not run into a *too many redirects* error. See: - -```php -public $globals = [ - 'before' => [ - //... - //... - 'force-reset' => ['except' => ['login*', 'register', 'auth/a/*', 'change-password', 'logout']] - ] -]; -``` -In the example above, it is assumed that the page you have created for users to change their password after successful login is **change-password**. - -> **Note** If you have grouped or changed the default format of the routes, ensure that your code matches the new format(s) in the **app/Config/Filter.php** file. - -For example, if you configured your routes like so: - -```php -$routes->group('accounts', static function($routes) { - service('auth')->routes($routes); -}); -``` -Then the global `before` filter for `session` should look like so: - -```php -public $globals = [ - 'before' => [ - // ... - 'session' => ['except' => ['accounts/login*', 'accounts/register', 'accounts/auth/a/*']] - ] -] -``` -The same should apply for the Rate Limiting and Forcing Password Reset. diff --git a/docs/quick_start_guide/authorization_flow.md b/docs/quick_start_guide/using_authorization.md similarity index 94% rename from docs/quick_start_guide/authorization_flow.md rename to docs/quick_start_guide/using_authorization.md index 568ca5094..c4d6d9f3a 100644 --- a/docs/quick_start_guide/authorization_flow.md +++ b/docs/quick_start_guide/using_authorization.md @@ -1,6 +1,6 @@ -# Authorization Flow +# Using Authorization -## Configure Config\AuthGroups +## Configuration ### Change Available Groups @@ -79,7 +79,8 @@ if (! auth()->user()->can('users.create')) { } ``` -> **Note** The example above can also be done through a [controller filter](https://codeigniter.com/user_guide/incoming/filters.html) if you want to apply it to multiple pages of your site. +> **Note** +> The example above can also be done through a [controller filter](https://codeigniter.com/user_guide/incoming/filters.html) if you want to apply it to multiple pages of your site. ## Adding a Group To a User diff --git a/docs/quick_start_guide/authentication_flow.md b/docs/quick_start_guide/using_session_auth.md similarity index 56% rename from docs/quick_start_guide/authentication_flow.md rename to docs/quick_start_guide/using_session_auth.md index d22383f38..76086a855 100644 --- a/docs/quick_start_guide/authentication_flow.md +++ b/docs/quick_start_guide/using_session_auth.md @@ -1,11 +1,13 @@ -# Authentication Flow +# Using Session Authenticator + +**Session** authenticator provides traditional ID/Password authentication. Learning any new authentication system can be difficult, especially as they get more flexible and sophisticated. This guide is intended to provide short examples for common actions you'll take when working with Shield. It is not intended to be the exhaustive documentation for each section. That's better handled through the area-specific doc files. > **Note** > The examples assume that you have run the setup script and that you have copies of the `Auth` and `AuthGroups` config files in your application's **app/Config** folder. -## Configure Config\Auth +## Configuration ### Configure Redirect URLs @@ -27,7 +29,7 @@ public array $redirects = [ ### Configure Remember-me Functionality -Remember-me functionality is enabled by default for the `Session` authenticator. While this is handled in a secure manner, some sites may want it disabled. You might also want to change how long it remembers a user and doesn't require additional login. +Remember-me functionality is enabled by default. While this is handled in a secure manner, some sites may want it disabled. You might also want to change how long it remembers a user and doesn't require additional login. ```php public array $sessionConfig = [ @@ -38,18 +40,10 @@ public array $sessionConfig = [ ]; ``` -### Change Access Token Lifetime - -By default, Access Tokens can be used for 1 year since the last use. This can be easily modified in the `Auth` config file. - -```php -public int $unusedTokenLifetime = YEAR; -``` - ### Enable Account Activation via Email > **Note** -> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../install.md#initial-setup). +> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../getting_started/install.md#initial-setup). By default, once a user registers they have an active account that can be used. You can enable Shield's built-in, email-based activation flow within the `Auth` config file. @@ -63,7 +57,7 @@ public array $actions = [ ### Enable Two-Factor Authentication > **Note** -> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../install.md#initial-setup). +> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../getting_started/install.md#initial-setup). Turned off by default, Shield's Email-based 2FA can be enabled by specifying the class to use in the `Auth` config file. @@ -74,35 +68,39 @@ public array $actions = [ ]; ``` -## Responding to Magic Link Logins +## Customizing Routes -> **Note** -> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../install.md#initial-setup). - -Magic Link logins allow a user that has forgotten their password to have an email sent with a unique, one-time login link. Once they've logged in you can decide how to respond. In some cases, you might want to redirect them to a special page where they must choose a new password. In other cases, you might simply want to display a one-time message prompting them to go to their account page and choose a new password. - -### Session Notification - -You can detect if a user has finished the magic link login by checking for a session value, `magicLogin`. If they have recently completed the flow, it will exist and have a value of `true`. +If you need to customize how any of the auth features are handled, you can still +use the `service('auth')->routes()` helper, but you will need to pass the `except` +option with a list of routes to customize: ```php -if (session('magicLogin')) { - return redirect()->route('set_password'); -} +service('auth')->routes($routes, ['except' => ['login', 'register']]); ``` -This value sticks around in the session for 5 minutes. Once you no longer need to take any actions, you might want to delete the value from the session. +Then add the routes to your customized controllers: ```php -session()->removeTempdata('magicLogin'); +$routes->get('login', '\App\Controllers\Auth\LoginController::loginView'); +$routes->get('register', '\App\Controllers\Auth\RegisterController::registerView'); ``` -### Event +Check your routes with the [spark routes](https://codeigniter.com/user_guide/incoming/routing.html#spark-routes) +command. -At the same time the above session variable is set, a `magicLogin` [event](https://codeigniter.com/user_guide/extending/events.html) is fired off that you may subscribe to. Note that no data is passed to the event as you can easily grab the current user from the `user()` helper or the `auth()->user()` method. +## Protecting Pages + +If you want to limit all routes (e.g. `localhost:8080/admin`, `localhost:8080/panel` and ...), you need to add the following code in the **app/Config/Filters.php** file. ```php -Events::on('magicLogin', static function () { +public $globals = [ + 'before' => [ + // ... + 'session' => ['except' => ['login*', 'register', 'auth/a/*']], + ], // ... -}); +]; ``` + +Check your filters with the [spark routes](https://codeigniter.com/user_guide/incoming/routing.html#spark-routes) +command. diff --git a/docs/auth_actions.md b/docs/references/auth_actions.md similarity index 100% rename from docs/auth_actions.md rename to docs/references/auth_actions.md diff --git a/docs/authentication.md b/docs/references/authentication.md similarity index 97% rename from docs/authentication.md rename to docs/references/authentication.md index e87c5d946..c1286ad4b 100644 --- a/docs/authentication.md +++ b/docs/references/authentication.md @@ -6,9 +6,8 @@ web apps and APIs. ## Available Authenticators -Shield ships with 2 authenticators that will serve several typical situations within web app development: the -Session authenticator, which uses username/email/password to authenticate against and stores it in the session, -and the Access Tokens authenticator which uses private access tokens passed in the headers. +Shield ships with 4 authenticators that will serve several typical situations within web app development. +You can see the [Authenticator List](../getting_started/authenticators.md). The available authenticators are defined in `Config\Auth`: @@ -18,6 +17,7 @@ public $authenticators = [ 'session' => Session::class, 'tokens' => AccessTokens::class, 'hmac' => HmacSha256::class, + // 'jwt' => JWT::class, ]; ``` @@ -73,7 +73,7 @@ Can return a custom bit of information. These will be detailed in the method des The Session authenticator stores the user's authentication within the user's session, and on a secure cookie on their device. This is the standard password-based login used in most web sites. It supports a -secure remember me feature, and more. This can also be used to handle authentication for +secure remember-me feature, and more. This can also be used to handle authentication for single page applications (SPAs). ### attempt() diff --git a/docs/authorization.md b/docs/references/authorization.md similarity index 94% rename from docs/authorization.md rename to docs/references/authorization.md index 571af598d..67d5af0df 100644 --- a/docs/authorization.md +++ b/docs/references/authorization.md @@ -57,7 +57,8 @@ public array $permissions = [ In order to grant any permissions to a group, they must have the permission assigned to the group, within the `AuthGroups` config file, under the `$matrix` property. -> **Note** This defines **group-level permissons**. +> **Note** +> This defines **group-level permissons**. The matrix is an associative array with the group name as the key, and an array of permissions that should be applied to that group. @@ -121,7 +122,8 @@ if (! $user->hasPermission('users.create')) { } ``` -> **Note** This method checks only **user-level permissions**, and does not check +> **Note** +> This method checks only **user-level permissions**, and does not check > group-level permissions. If you want to check if the user can do something, > use the `$user->can()` method instead. @@ -150,7 +152,8 @@ $routes->group('admin', ['filter' => 'group:admin,superadmin'], static function Note that the options (`filter`) passed to the outer `group()` are not merged with the inner `group()` options. -> **Note** If you set more than one filter to a route, you need to enable +> **Note** +> If you set more than one filter to a route, you need to enable > [Multiple Filters](https://codeigniter.com/user_guide/incoming/routing.html#multiple-filters). ## Managing User Permissions @@ -193,7 +196,8 @@ Returns all **user-level** permissions this user has assigned directly to them. $user->getPermissions(); ``` -> **Note** This method does not return **group-level permissions**. +> **Note** +> This method does not return **group-level permissions**. ## Managing User Groups @@ -246,7 +250,8 @@ if ($user->isActivated()) { } ``` -> **Note** If no activator is specified in the `Auth` config file, `actions['register']` property, then this will always return `true`. +> **Note** +> If no activator is specified in the `Auth` config file, `actions['register']` property, then this will always return `true`. You can check if a user has not been activated yet via the `isNotActivated()` method. diff --git a/docs/references/controller_filters.md b/docs/references/controller_filters.md new file mode 100644 index 000000000..e10adc888 --- /dev/null +++ b/docs/references/controller_filters.md @@ -0,0 +1,108 @@ +# Controller Filters + +## Provided Filters + +> **Note** +> These filters are already loaded for you by the [registrar](https://codeigniter.com/user_guide/general/configuration.html#registrars) class located at **src/Config/Registrar.php**. + +The [Controller Filters](https://codeigniter.com/user_guide/incoming/filters.html) you can use to protect your routes Shield provides are: + +```php +public $aliases = [ + // ... + 'session' => \CodeIgniter\Shield\Filters\SessionAuth::class, + 'tokens' => \CodeIgniter\Shield\Filters\TokenAuth::class, + 'hmac' => \CodeIgniter\Shield\Filters\HmacAuth::class, + 'chain' => \CodeIgniter\Shield\Filters\ChainAuth::class, + 'auth-rates' => \CodeIgniter\Shield\Filters\AuthRates::class, + 'group' => \CodeIgniter\Shield\Filters\GroupFilter::class, + 'permission' => \CodeIgniter\Shield\Filters\PermissionFilter::class, + 'force-reset' => \CodeIgniter\Shield\Filters\ForcePasswordResetFilter::class, + 'jwt' => \CodeIgniter\Shield\Filters\JWTAuth::class, +]; +``` + +| Filters | Description | +|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| session | The `Session` authenticator. | +| tokens | The `AccessTokens` authenticator. | +| chained | The filter will check authenticators in sequence to see if the user is logged in through either of authenticators, allowing a single API endpoint to work for both an SPA using session auth, and a mobile app using access tokens. | +| jwt | The `JWT` authenticator. See [JWT Authentication](../addons/jwt.md). | +| hmac | The `HMAC` authenticator. See [HMAC Authentication](../guides/api_hmac_keys.md). | +| auth-rates | Provides a good basis for rate limiting of auth-related routes. | +| group | Checks if the user is in one of the groups passed in. | +| permission | Checks if the user has the passed permissions. | +| force-reset | Checks if the user requires a password reset. | + +These can be used in any of the [normal filter config settings](https://codeigniter.com/user_guide/incoming/filters.html#globals), or [within the routes file](https://codeigniter.com/user_guide/incoming/routing.html#applying-filters). + +## Configure Controller Filters + +### Protect All Pages + +If you want to limit all routes (e.g. `localhost:8080/admin`, `localhost:8080/panel` and ...), you need to add the following code in the **app/Config/Filters.php** file. + +```php +public $globals = [ + 'before' => [ + // ... + 'session' => ['except' => ['login*', 'register', 'auth/a/*']], + ], + // ... +]; +``` + +### Rate Limiting + +To help protect your authentication forms from being spammed by bots, it is recommended that you use +the `auth-rates` filter on all of your authentication routes. This can be done with the following +filter setup: + +```php +public $filters = [ + 'auth-rates' => [ + 'before' => [ + 'login*', 'register', 'auth/*' + ] + ] +]; +``` + +### Forcing Password Reset + +If your application requires a force password reset functionality, ensure that you exclude the auth pages and the actual password reset page from the `before` global. This will ensure that your users do not run into a *too many redirects* error. See: + +```php +public $globals = [ + 'before' => [ + //... + //... + 'force-reset' => ['except' => ['login*', 'register', 'auth/a/*', 'change-password', 'logout']] + ] +]; +``` +In the example above, it is assumed that the page you have created for users to change their password after successful login is **change-password**. + +> **Note** +> If you have grouped or changed the default format of the routes, ensure that your code matches the new format(s) in the **app/Config/Filter.php** file. + +For example, if you configured your routes like so: + +```php +$routes->group('accounts', static function($routes) { + service('auth')->routes($routes); +}); +``` + +Then the global `before` filter for `session` should look like so: + +```php +public $globals = [ + 'before' => [ + // ... + 'session' => ['except' => ['accounts/login*', 'accounts/register', 'accounts/auth/a/*']] + ] +] +``` + +The same should apply for the Rate Limiting and Forcing Password Reset. diff --git a/docs/events.md b/docs/references/events.md similarity index 100% rename from docs/events.md rename to docs/references/events.md diff --git a/docs/references/magic_link_login.md b/docs/references/magic_link_login.md new file mode 100644 index 000000000..361c7aa38 --- /dev/null +++ b/docs/references/magic_link_login.md @@ -0,0 +1,57 @@ +# Magic Link Login + +Magic Link Login is a feature that allows users to log in if they forget their +password. + +## Configuration + +### Configure Magic Link Login Functionality + +Magic Link Login functionality is enabled by default. +You can change it within the **app/Config/Auth.php** file. + +```php +public bool $allowMagicLinkLogins = true; +``` + +### Magic Link Lifetime + +By default, Magic Link can be used for 1 hour. This can be easily modified +in the **app/Config/Auth.php** file. + +```php +public int $magicLinkLifetime = HOUR; +``` + +## Responding to Magic Link Logins + +> **Note** +> You need to configure **app/Config/Email.php** to allow Shield to send emails. See [Installation](../getting_started/install.md#initial-setup). + +Magic Link logins allow a user that has forgotten their password to have an email sent with a unique, one-time login link. Once they've logged in you can decide how to respond. In some cases, you might want to redirect them to a special page where they must choose a new password. In other cases, you might simply want to display a one-time message prompting them to go to their account page and choose a new password. + +### Session Notification + +You can detect if a user has finished the magic link login by checking for a session value, `magicLogin`. If they have recently completed the flow, it will exist and have a value of `true`. + +```php +if (session('magicLogin')) { + return redirect()->route('set_password'); +} +``` + +This value sticks around in the session for 5 minutes. Once you no longer need to take any actions, you might want to delete the value from the session. + +```php +session()->removeTempdata('magicLogin'); +``` + +### Event + +At the same time the above session variable is set, a `magicLogin` [event](https://codeigniter.com/user_guide/extending/events.html) is fired off that you may subscribe to. Note that no data is passed to the event as you can easily grab the current user from the `user()` helper or the `auth()->user()` method. + +```php +Events::on('magicLogin', static function () { + // ... +}); +``` diff --git a/docs/session_auth_event_and_logging.md b/docs/references/session_auth_event_and_logging.md similarity index 100% rename from docs/session_auth_event_and_logging.md rename to docs/references/session_auth_event_and_logging.md diff --git a/docs/testing.md b/docs/references/testing.md similarity index 100% rename from docs/testing.md rename to docs/references/testing.md diff --git a/docs/guides/banning_users.md b/docs/user_management/banning_users.md similarity index 100% rename from docs/guides/banning_users.md rename to docs/user_management/banning_users.md diff --git a/docs/guides/forcing_password_reset.md b/docs/user_management/forcing_password_reset.md similarity index 100% rename from docs/guides/forcing_password_reset.md rename to docs/user_management/forcing_password_reset.md diff --git a/docs/quick_start_guide/managing_users.md b/docs/user_management/managing_users.md similarity index 80% rename from docs/quick_start_guide/managing_users.md rename to docs/user_management/managing_users.md index 84c57815b..9d73385d3 100644 --- a/docs/quick_start_guide/managing_users.md +++ b/docs/user_management/managing_users.md @@ -1,6 +1,6 @@ # Managing Users -Since Shield uses a more complex user setup than many other systems, separating [User Identities](../concepts.md#user-identities) from the user accounts themselves. This quick overview should help you feel more confident when working with users on a day-to-day basis. +Since Shield uses a more complex user setup than many other systems, separating [User Identities](../getting_started/concepts.md#user-identities) from the user accounts themselves. This quick overview should help you feel more confident when working with users on a day-to-day basis. ## Creating Users @@ -37,7 +37,8 @@ $users = auth()->getProvider(); $users->delete($user->id, true); ``` -> **Note** The User rows use [soft deletes](https://codeigniter.com/user_guide/models/model.html#usesoftdeletes) so they are not actually deleted from the database unless the second parameter is `true`, like above. +> **Note** +> The User rows use [soft deletes](https://codeigniter.com/user_guide/models/model.html#usesoftdeletes) so they are not actually deleted from the database unless the second parameter is `true`, like above. ## Editing a User diff --git a/mkdocs.yml b/mkdocs.yml index f18ca9d7c..468d7e210 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,34 +39,39 @@ extra_javascript: nav: - Home: index.md - Getting Started: - - Concepts: concepts.md - - Installation: install.md + - Concepts: getting_started/concepts.md + - getting_started/install.md + - getting_started/authenticators.md + - getting_started/configuration.md - Quick Start Guide: - - quick_start_guide/authentication_flow.md - - quick_start_guide/authorization_flow.md - - quick_start_guide/managing_users.md - - References: - - Authentication: authentication.md - - Authorization: authorization.md - - Auth Actions: auth_actions.md - - Events: events.md - - Testing: testing.md - - session_auth_event_and_logging.md + - quick_start_guide/using_session_auth.md + - quick_start_guide/using_authorization.md - Customization: - customization/table_names.md - customization/route_config.md - customization/redirect_urls.md - - customization/extending_controllers.md - - customization/integrating_custom_view_libs.md - customization/validation_rules.md - customization/user_provider.md + - customization/extending_controllers.md + - customization/integrating_custom_view_libs.md - customization/login_identifier.md + - User Management: + - user_management/managing_users.md + - user_management/forcing_password_reset.md + - user_management/banning_users.md - Guides: - - guides/forcing_password_reset.md - - guides/banning_users.md - guides/api_tokens.md - guides/api_hmac_keys.md - guides/mobile_apps.md - guides/strengthen_password.md + - References: + - references/controller_filters.md + - references/authentication.md + - references/auth_actions.md + - references/magic_link_login.md + - references/authorization.md + - references/events.md + - references/testing.md + - references/session_auth_event_and_logging.md - Addons: - JWT Authentication: addons/jwt.md