This package is forked from ArranJacques/laravel-aws-cognito-auth but updated to Laravel 8.
A simple authentication package for Laravel 8 and 9 for authenticating users in Amazon Cognito User Pools.
This is package works with Laravel's native authentication system and allows the authentication of users that are already registered in Amazon Cognito User Pools. It does not provide functionality for user management, i.e., registering user's into User Pools, password resets, etc.
This package makes use of the aws-sdk-php-laravel package. As well as setting up and configuring this package you'll also need to configure aws-sdk-php-laravel for the authentication to work. Instructions on how to do this are below. If you've already installed, set up and configured aws-sdk-php-laravel you can skip the parts where it's mentioned below.
You can install the package via composer:
Laravel | Version |
---|---|
8 | 1.0.0 |
9 | 2.0.0 |
composer require zarate-systems/laravel-cognito-auth
Open the app/Http/Kernel.php
file and replace the default \Illuminate\Session\Middleware\AuthenticateSession::class
middleware with \ZarateSystems\LaravelCognitoAuth\AuthenticateSession::class
protected $middlewareGroups = [
'web' => [
...
\ZarateSystems\LaravelCognitoAuth\AuthenticateSession::class,
...
],
];
Publish the config file as well as the aws-sdk-php-laravel config file to your config directory by running:
php artisan vendor:publish --provider="ZarateSystems\LaravelCognitoAuth\LaravelCognitoAuthServiceProvider"
php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider"
Open the config/auth.php
file and set your default guard's driver to aws-cognito
. Out of the box the default guard is web
so your config/auth.php
would look something like:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
Change the driver.
'guards' => [
'web' => [
'driver' => 'aws-cognito',
'provider' => 'users',
],
],
Add the next envioremnt variables to .env
file.
AWS_COGNITO_IDENTITY_POOL_ID=YOUR_POOL_ID
AWS_COGNITO_IDENTITY_APP_CLIENT_ID=YOUR_CLIENT_ID
- Note
When creating an App for your User Pool the default Refresh Token Expiration time is 30 days. If you've set a different expiration time for your App then make sure you update the
refresh-token-expiration
value in theconfig/aws-cognito-auth.php
file.
'apps' => [
'default' => [
'client-id' => env('AWS_COGNITO_IDENTITY_APP_CLIENT_ID', ''),
'refresh-token-expiration' => <num-of-days>,
],
],
Open the config/aws.php
file and set the region
value to whatever region your User Pool is in. The default config/aws.php
file that is created when using the php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider"
command doesn't include the IAM credential properties so you'll need to add them manually.
Add the following to the .env
file.
AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY
AWS_REGION=YOUR_DEFAULT_REGION
Where AWS_ACCESS_KEY_ID
is an IAM user Access Key Id and AWS_SECRET_ACCESS_KEY
is the corresponding Secret key.
Cognito is not treated as a "database of users", and is only used to authorize the users. A request to Cognito is not made unless the user already exists in the app's database. This means you'll still need a users table populated with the users that you want to authenticate. At a minimum this table will need an id
, email
and remember_token
field.
In Cognito every user has a username
. When authenticating with Cognito this package will need one of the user's attributes to match the user's Congnito username. By default it uses the user's email
attribute.
If you want to use a different attribute to store the user's Cognito username then you can do so by first adding a new field to your users
table, for example cognito_username, and then setting the username-attribute
in the config/aws-cognito-auth.php
file to be the name of that field.
Once installed and configured the authentication works the same as it doesn natively in Laravel. See Laravel's documentation for full details.
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
]);
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], true);
Auth::user();
Auth::logout();
As well as the default functionality some extra methods are made available for accessing the user's Cognito access token, id token, etc:
Auth::getCognitoAccessToken();
Auth::getCognitoIdToken();
Auth::getCognitoRefreshToken();
Auth::getCognitoTokensExpiryTime();
Auth::getCognitoRefreshTokenExpiryTime();
AWS Cognito may fail to authenticate for a number of reasons, from simply entering the wrong credentials, or because additional checks or actions are required before the user can be successfully authenticated.
So that you can deal with failed attempts appropriately several options are available to you within the package that dictate how failed attempts should be handled.
You can specify how failed attempts should be handled by passing an additional $errorHandler
argument when calling the Auth::attempt()
and Auth::validate()
methods.
Auth::attempt(array $credentials, [bool $remember], [$errorHandler]);
Auth::validate(array $credentials, [$errorHandler]);
If an $errorHandler
isn't passed then all failed authentication attempts will be handled and suppressed internally, and both the Auth::attempt()
and Auth::validate()
methods will simply return true or false as to whether the authentication attempt was successful.
To have the Auth::attempt()
and Auth::validate()
methods throw an exception pass AWS_COGNITO_AUTH_THROW_EXCEPTION
as the $errorHandler
argument.
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_THROW_EXCEPTION);
Auth::validate([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], AWS_COGNITO_AUTH_THROW_EXCEPTION);
If the authentication fails then a \ZarateSystems\LaravelCognitoAuth\AuthAttemptException
exception will be thrown, which can be used to access the underlying error by calling the exception's getResponse()
method. About AuthAttemptException.
try {
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_THROW_EXCEPTION);
} catch (\ZarateSystems\LaravelCognitoAuth\AuthAttemptException $exception) {
$response = $exception->getResponse();
// Handle error...
}
To have the Auth::attempt()
and Auth::validate()
methods return an attempt object pass AWS_COGNITO_AUTH_RETURN_ATTEMPT
as the $errorHandler
argument.
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_RETURN_ATTEMPT);
Auth::validate([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], AWS_COGNITO_AUTH_RETURN_ATTEMPT);
When using AWS_COGNITO_AUTH_RETURN_ATTEMPT
both methods will return an instance of \ZarateSystems\LaravelCognitoAuth\AuthAttempt
, which can be used to check if the authentication attempt was successful or not.
$attempt = Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_RETURN_ATTEMPT);
if ($attempt->successful()) {
// Do something...
} else {
$response = $attempt->getResponse();
// Handle error...
}
For unsuccessful authentication attempts the attempt instance's getResponse()
method can be used to access the underlying error. This method will return an array of data that will contain different values depending on the reason for the failed attempt.
In events where the AWS Cognito API has thrown an exception, such as when invalid credentials are used, the array that is returned will contain the original exception.
[
'exception' => CognitoIdentityProviderException {...},
]
In events where the AWS Cognito API has failed to authenticate for some other reason, for example because a challenge must be passed, then the array that is returned will contain the details of the error.
[
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'Session' => '...',
'ChallengeParameters' => [...],
]
To handle failed authentication attempts with a closure pass one as the Auth::attempt()
and Auth::validate()
methods' $errorHandler
argument.
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, function (\ZarateSystems\LaravelCognitoAuth\AuthAttemptException $exception) {
$response = $exception->getResponse();
// Handle error...
});
Auth::validate([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], function (\ZarateSystems\LaravelCognitoAuth\AuthAttemptException $exception) {
$response = $exception->getResponse();
// Handle error...
};
If the authentication fails then the closure will be run and will be passed an \ZarateSystems\LaravelCognitoAuth\AuthAttemptException
instance, which can be used to access the underlying error by calling the exception's getResponse()
method. About AuthAttemptException.
To handle failed authentication attempts with a custom class pass the classes name as the Auth::attempt()
and Auth::validate()
methods' $errorHandler
argument.
Auth::attempt([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], false, \App\MyCustomErrorHandler::class);
Auth::validate([
'email' => '[email protected]',
'password' => 'xxxxxxxxxx',
], \App\MyCustomErrorHandler::class);
The error handler class should have a handle()
method, which will be called when an authentication attempt fails. The handle()
method will be passed an \ZarateSystems\LaravelCognitoAuth\AuthAttemptException
instance, which can be used to access the underlying error by calling the exception's getResponse()
method. About AuthAttemptException.
<?php
namespace App;
use ZarateSystems\LaravelCognitoAuth\AuthAttemptException;
class MyCustomErrorHandler
{
public function handle(AuthAttemptException $exception)
{
$response = $exception->getResponse();
// Handle error...
}
}
As well defining the error handler in line, you can also define a default error handler in the config/aws-cognito-auth.php
file. The same error handling methods are available as detailed above. When using AWS_COGNITO_AUTH_THROW_EXCEPTION
or AWS_COGNITO_AUTH_RETURN_ATTEMPT
set the value as a string, do not use the constant.
Throw Exception:
'errors' => [
'handler' => 'AWS_COGNITO_AUTH_THROW_EXCEPTION',
],
Return Attempt:
'errors' => [
'handler' => 'AWS_COGNITO_AUTH_RETURN_ATTEMPT',
],
Use a Closure:
'errors' => [
'handler' => function (\ZarateSystems\LaravelCognitoAuth\AuthAttemptException $exception) {
$exception->getResponse();
// Do something...
},
],
Use a Custom Class:
'errors' => [
'handler' => \App\MyCustomErrorHandler::class,
],
An \ZarateSystems\LaravelCognitoAuth\AuthAttemptException
exception will be thrown when using the AWS_COGNITO_AUTH_THROW_EXCEPTION
error handler, or will be passed as an argument to a closure when using the Clousre
method of error handling.
The exception's getResponse()
method will return an array of data that will contain different values depending on the reason for the failed attempt.
In events where the AWS Cognito API has thrown an exception, such as when invalid credentials are used, the array that is returned will contain the original exception.
[
'exception' => CognitoIdentityProviderException {...},
]
In events where the AWS Cognito API has failed to authenticate for some other reason, for example because a challenge must be passed, the array that is returned will contain the details of the error.
[
'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
'Session' => '...',
'ChallengeParameters' => [...],
]
Please see CHANGELOG for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
This package was generated using the Laravel Package Boilerplate.