AWS Cognito package using the AWS SDK for PHP/Laravel

Overview

EllaiSys AWS Cloud Capability

Laravel Package to manage Web and API authentication with AWS Cognito

AWS Cognito package using the AWS SDK for PHP

Latest Version on Packagist Release Date Total Downloads APM

This package provides a simple way to use AWS Cognito authentication in Laravel 7.x for Web and API Auth Drivers. The idea of this package, and some of the code, is based on the package from Pod-Point which you can find here: Pod-Point/laravel-cognito-auth, black-bits/laravel-cognito-auth and tymondesigns/jwt-auth.

We decided to use it and contribute it to the community as a package, that encourages standarised use and a RAD tool for authentication using AWS Cognito.

Features

  • Registration and Confirmation E-Mail
  • Forced password change at first login (configurable)
  • Login
  • Remember Me Cookie
  • Single Sign On
  • Forgot Password
  • User Deletion
  • Edit User Attributes
  • Reset User Password
  • Confirm Sign Up
  • Easy API Token handling (uses the cache driver)
  • DynamoDB support for Web Sessions and API Tokens (useful for server redundency OR multiple containers)
  • Easy configuration of Token Expiry (Manage using the cognito console, no code or configurations needed)

Installation

You can install the package via composer.

composer require ellaisys/aws-cognito

Laravel 5.4 and before

Using a version prior to Laravel 5.5 you need to manually register the service provider.

    // config/app.php
    'providers' => [
        ...
        Ellaisys\Cognito\Providers\AwsCognitoServiceProvider::class,
        
    ];

Next you can publish the config and the view.

    php artisan vendor:publish --provider="Ellaisys\Cognito\Providers\AwsCognitoServiceProvider"

Last but not least you want to change the auth driver. To do so got to your config\auth.php file and change it to look the following:

    'guards' => [
        'web' => [
            'driver' => 'cognito-session', // This line is important for using AWS Cognito as Web Driver
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'cognito-token', // This line is important for using AWS Cognito as API Driver
            'provider' => 'users',
        ],
    ],

Cognito User Pool

In order to use AWS Cognito as authentication provider, you require a Cognito User Pool.

If you haven't created one already, go to your Amazon management console and create a new user pool.

Next, generate an App Client. This will give you the App client id and the App client secret you need for your .env file.

IMPORTANT: Don't forget to activate the checkbox to Enable sign-in API for server-based Authentication. The Auth Flow is called: ADMIN_USER_PASSWORD_AUTH (formerly ADMIN_NO_SRP_AUTH)

You also need a new IAM Role with the following Access Rights:

  • AmazonCognitoDeveloperAuthenticatedIdentities
  • AmazonCognitoPowerUser
  • AmazonESCognitoAccess

From this user you can fetch the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

Cognito API configuration

Add the following fields to your .env file and set the values according to your AWS settings:

    # AWS configurations for cloud storage
    AWS_ACCESS_KEY_ID="Axxxxxxxxxxxxxxxxxxxxxxxx6"
    AWS_SECRET_ACCESS_KEY="mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+"

    # AWS Cognito configurations
    AWS_COGNITO_CLIENT_ID="6xxxxxxxxxxxxxxxxxxxxxxxxr"
    AWS_COGNITO_CLIENT_SECRET="1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1"
    AWS_COGNITO_USER_POOL_ID="xxxxxxxxxxxxxxxxx"
    AWS_COGNITO_REGION="xxxxxxxxxxx" //optional - default value is 'us-east-1'
    AWS_COGNITO_VERSION="latest" //optional - default value is 'latest'

For more details on how to find AWS_COGNITO_CLIENT_ID, AWS_COGNITO_CLIENT_SECRET and AWS_COGNITO_USER_POOL_ID for your application, please refer COGNITOCONFIG File

Importing existing users into the Cognito Pool

If you are already working on an existing project and want to integrate Cognito you have to import a user csv file to your Cognito Pool.

Usage

Our package is providing you 6 traits you can just add to your Auth Controllers to get our package running.

  • Ellaisys\Cognito\Auth\AuthenticatesUsers
  • Ellaisys\Cognito\Auth\RegistersUsers
  • Ellaisys\Cognito\Auth\ResetsPasswords
  • Ellaisys\Cognito\Auth\RespondsMFAChallenge
  • Ellaisys\Cognito\Auth\SendsPasswordResetEmails
  • Ellaisys\Cognito\Auth\VerifiesEmails

In the simplest way you just go through your Auth Controllers and change namespaces from the traits which are currently implemented from Laravel.

You can change structure to suit your needs. Please be aware of the @extend statement in the blade file to fit into your project structure. At the current state you need to have those 4 form fields defined in here. Those are token, email, password, password_confirmation.

Single Sign-On

With our package and AWS Cognito we provide you a simple way to use Single Sign-Ons. For configuration options take a look at the config cognito.php.

When you want SSO enabled and a user tries to login into your application, the package checks if the user exists in your AWS Cognito pool. If the user exists, he will be created automatically in your database provided the add_missing_local_user_sso is to true, and is logged in simultaneously.

That's what we use the fields sso_user_model and cognito_user_fields for. In sso_user_model you define the class of your user model. In most cases this will simply be App\User.

With cognito_user_fields you can define the fields which should be stored in Cognito. Put attention here. If you define a field which you do not send with the Register Request this will throw you an InvalidUserFieldException and you won't be able to register.

Now that you have registered your users with their attributes in the AWS Cognito pool and your database and you want to attach a second app which should use the same pool. Well, that's actually pretty easy. You can use the API provisions that allows multiple projects to consume the same AWS Cognito pool.

*IMPORTANT: if your users table has a password field you are not going to need this anymore. What you want to do is set this field to be nullable, so that users can be created without passwords. From now on, Passwords are stored in Cognito.

Any additional registration data you have, for example firstname, lastname needs to be added in cognito.php cognito_user_fields config to be pushed to Cognito. Otherwise they are only stored locally and are not available if you want to use Single Sign On's.*

Middleware configuration for API Routes

In case you are using this library as API driver, you can register the middleware into the kernal.php in the $routeMiddleware

    protected $routeMiddleware = [
        ...
        'aws-cognito' => \Ellaisys\Cognito\Http\Middleware\AwsCognitoAuthenticate::class
    ]

To use the middleware into the Web routes, you can use the std auth middleware as shown below

    Route::middleware('auth')->get('user', 'NameOfTheController@functionName');

To use the middleware into the API routes, as shown below

    Route::middleware('aws-cognito')->get('user', 'NameOfTheController@functionName');

Registering Users

As a default, if you are registering a new user with Cognito, Cognito will send you an email during signUp that includes the username and temporary password for the users to verify themselves.

Using this library in conjunction with AWS Lambda, once can look to customize the email template and content. The email template can be text or html based. The Lambda code for not included in this code repository. You can create your own. Any object (array) that you pass to the registration method is transferred as is to the lambda function, we are not prescriptive about the attribute names.

We have made is very easy for anyone to use the default behaviour.

  1. You don't need to create an extra field to store the verification token.
  2. You don't have to bother about the Sessions or API tokens, they are managed for you. The session or token is managed via the standard mechanism of Laravel. You have the liberty to keep it where ever you want, no security loop holes.
  3. If you use the trait provided by us 'Ellaisys\Cognito\Auth\RegistersUsers', the code will be limited to just a few lines
  4. if you are using the Laravel scafolding, then make the password nullable in DB or drop it from schema. Passwords will be only managed by AWS Cognito.
    use Ellaisys\Cognito\Auth\RegistersUsers;

    class UserController extends BaseController
    {
        use RegistersUsers;

        public function register(Request $request)
        {
            $validator = $request->validate([
                'name' => 'required|max:255',
                'email' => 'required|email|max:64|unique:users',
                'password' => 'sometimes|confirmed|min:6|max:64',
            ]);

            //Create credentials object
            $collection = collect($request->all());
            $data = $collection->only('name', 'email', 'password'); //passing 'password' is optional.

            //Register User in cognito
            if ($cognitoRegistered=$this->createCognitoUser($data)) {

                //If successful, create the user in local db
                User::create($collection->only('name', 'email'));
            } //End if

            //Redirect to view
            return view('login');
        }
    }
  1. You don't need to turn off Cognito to send you emails. We rather propose the use of AWS Cognito or AWS SMS mailers, such that use credentials are always secure.

User Authentication

We have provided you with a useful trait that make the authentication very simple (with Web or API routes). You don't have to worry about any additional code to manage sessions and token (for API).

The trait takes in some additional parameters, refer below the function signature of the trait. Note that the function takes the object of Illuminate\Support\Collection instead of Illuminate\Http\Request. This will allow you to use this function in any tier of the code.

Also, the 'guard' name reference is passed, so that you can reuse the function for multiple guard drivers in your project. The function has the capability to handle the Session and Token Guards with multiple drivers and providers as defined in /config/auth.php

    namespace Ellaisys\Cognito\Auth;

    protected function attemptLogin (
        Collection $request, string $guard='web', 
        string $paramUsername='email', string $paramPassword='password', 
        bool $isJsonResponse=false
    ) {
        ...
        ...


        ...
    }

In case you want to use this trait for Web login, you can write the code as shown below in the AuthController.php

    namespace App\Http\Controllers;

    ...

    use Ellaisys\Cognito\AwsCognitoClaim;
    use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers;

    class AuthController extends Controller
    {
        use CognitoAuthenticatesUsers;

        /**
         * Authenticate User
         * 
         * @throws \HttpException
         * 
         * @return mixed
         */
        public function login(\Illuminate\Http\Request $request)
        {
            ...

            //Convert request to collection
            $collection = collect($request->all());

            //Authenticate with Cognito Package Trait (with 'web' as the auth guard)
            if ($response = $this->attemptLogin($collection, 'web')) {
                if ($response===true) {
                    return redirect(route('home'))->with('success', true);
                } else if ($response===false) {
                    // If the login attempt was unsuccessful you may increment the number of attempts
                    // to login and redirect the user back to the login form. Of course, when this
                    // user surpasses their maximum number of attempts they will get locked out.
                    //
                    //$this->incrementLoginAttempts($request);
                    //
                    //$this->sendFailedLoginResponse($collection, null);
                } else {
                    return $response;
                } //End if
            } //End if

        } //Function ends

        ...
    } //Class ends

In case you want to use this trait for API based login, you can write the code as shown below in the AuthApiController.php

    namespace App\Api\Controller;

    ...

    use Ellaisys\Cognito\AwsCognitoClaim;
    use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers;

    class AuthApiController extends Controller
    {
        use CognitoAuthenticatesUsers;

        /**
         * Authenticate User
         * 
         * @throws \HttpException
         * 
         * @return mixed
         */
        public function login(\Illuminate\Http\Request $request)
        {
            ...

            //Convert request to collection
            $collection = collect($request->all());

            //Authenticate with Cognito Package Trait (with 'api' as the auth guard)
            if ($claim = $this->attemptLogin($collection, 'api', 'username', 'password', true)) {
                if ($claim instanceof AwsCognitoClaim) {
                    return $claim->getData();
                } else {
                    return response()->json(['status' => 'error', 'message' => $claim], 400);
                } //End if
            } //End if

        } //Function ends


        ...
    } //Class ends

Delete User

If you want to give your users the ability to delete themselves from your app you can use our deleteUser function from the CognitoClient.

To delete the user you should call deleteUser and pass the email of the user as a parameter to it. After the user has been deleted in your cognito pool, delete your user from your database too.

        $cognitoClient->deleteUser($user->email);
        $user->delete();

We have implemented a new config option delete_user, which you can access through AWS_COGNITO_DELETE_USER env var. If you set this config to true, the user is deleted in the Cognito pool. If it is set to false, it will stay registered. Per default this option is set to false. If you want this behaviour you should set USE_SSO to true to let the user restore themselves after a successful login.

To access our CognitoClient you can simply pass it as a parameter to your Controller Action where you want to perform the deletion.

    public function deleteUser(Request $request, AwsCognitoClient $client)

Laravel will take care of the dependency injection by itself.

    IMPORTANT: You want to secure this action by maybe security questions, a second delete password or by confirming 
    the email address.

Storing Web Sessions or API Tokens in DynamoDB (Useful for multiserver/container implementation)

If you have a deployment architecture, that involves multiple servers and you want to maintain the web sessions or API tokens across the servers, you can use the AWS DynamoDB. The library is capable of handling the DynamoDB with ease. All that you need to do is create the table in AWS DynamoDB and change a few configurations.

Creating a new table in AWS DynamoDB

  1. Go to the AWS Console and create a new table.
  2. Enter the unique table name as per your preferences.
  3. The primary key (or partition key) should be key of type string
  4. Use default settings and click the Create button

Update the .env file for Dynamo DB configurations

Add/Edit the following fields to your .env file and set the values according to your AWS settings:

    # Cache Configuration
    CACHE_DRIVER="dynamodb"
    DYNAMODB_CACHE_TABLE="table-name-of-your-choice" //This should match the table name provided above

    # Session Configuration
    SESSION_DRIVER="dynamodb"
    SESSION_LIFETIME=120
    SESSION_DOMAIN="set-your-domain-name" //The domain name can be as per your preference
    SESSION_SECURE_COOKIE=true

    # DynamoDB Configuration
    DYNAMODB_ENDPOINT="https://dynamodb.us-west-2.amazonaws.com" // You can change the endpoint based of different regions

Refer the AWS DynamoDB Documentation and refer the endpoints provided in Service endpoints section.

Update the DynamoDB table for the TTL columns as expires_at

Automatic User Password update for API usage (for New Cognito Users)

In case of the new cognito users, the AWS SDK will send a session key and the user is expected to change the password, in a forced mode. Make sure you force the users to change the password for the first login by new cognito user.

However, if you have an API based implementation, and want to automatically authenticate the user without forcing the password change, you may do that with below setting fields to your .env file

    AWS_COGNITO_FORCE_PASSWORD_CHANGE_API=false     //Make true for forcing password change
    AWS_COGNITO_FORCE_PASSWORD_AUTO_UPDATE_API=true //Make false for stopping auto password change

Changelog

Please see CHANGELOG for more information on what has changed recently.

Security

If you discover any security related issues, please email [email protected] and also add it to the issue tracker.

Credits

Support us

EllaiSys is a web and consulting agency specialized in Cloud Computing (AWS and Azure), DevOps, and Product Engneering. We specialize into LAMP and Microsoft stack development. You'll find an overview of what we do on our website.

License

The MIT License (MIT). Please see License File for more information.

Disclaimer

This package is currently in production ready mode with already a few implementations done. We would be happy to hear from you, about the defects or new feature enhancements. However, this being a free support, we would not be able to commit to support SLAs or timelines.

Comments
  • InvalidParameterException when login

    InvalidParameterException when login

    Sorry I am using your library for my project. Creating a new account is very convenient. But I have difficulty with login. I tried to fix it in many ways but they all say InvalidParameterException. Please help me. Thank you

    enhancement 
    opened by ducnguyenminu 16
  • Verification Email not receiving

    Verification Email not receiving

    I used the package and follow the steps in documentation to register new users. It is successfully registered but my user is not receiving verification email. When i checked UserPool via console, it seems like user's email is already verified. I think that is the reason why my user is not receiving verification email link via email

    I have configured UserPool for receiving email verification link

    When i checked package code, i found we are forcefully setting email_verified as true in the file src/AwsCognitoClient.php

           //Force validate email
            if ($attributes['email']) {
                $attributes['email_verified'] = 'true';
            } 
    

    I doubt this is the reason why i am not receiving verification email. I don't want any user got automatically verified

    Any suggestions?

    bug 
    opened by hafsalmetvr 9
  • InvalidSignatureException during registration

    InvalidSignatureException during registration

    i have done the most basic setup of the package and cognito and tried to register an user. out of the box i am getting the following error:

    
    "message": "Error executing \"AdminCreateUser\" on \"https://cognito-idp.eu-central-1.amazonaws.com\"; AWS HTTP error: Client error: `POST https://cognito-idp.eu-central-1.amazonaws.com` resulted in a `400 Bad Request` response:\n{\"__type\":\"InvalidSignatureException\",\"message\":\"The request signature we calculated does not match the signature you pr (truncated...)\n InvalidSignatureException (client): The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. - {\"__type\":\"InvalidSignatureException\",\"message\":\"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\"}",
        "exception": "Aws\\CognitoIdentityProvider\\Exception\\CognitoIdentityProviderException",
    
    

    AWS_ACCESS_KEY ID and SECRET have Administrator access just to rule out the permission issue.

    do you have any suggestions? what am i doing wrong?

    i think the issue is on cognito side since the sdk is throwing the error and not your package

    Screenshot 2022-01-04 at 22 36 34 Screenshot 2022-01-04 at 22 37 05 Screenshot 2022-01-04 at 22 39 22
    class RegisterController extends ApiBaseController
    {
        use RegistersUsers;
    
        public function __invoke(Request $request)
        {
            $validator = $request->validate([
                'email' => 'required|email|max:64|unique:users',
                'password' => 'required|confirmed|min:8|max:64'
            ]);
    
            $collection = collect($request->all());
    
            $data = $collection->only('name', 'email', 'password'); //passing 'password' is optional.
    
            try {
                if ($cognitoRegistered = $this->createCognitoUser($data)) {
                    User::create($collection->only('email'));
                    return response()->json($cognitoRegistered);
                }
            } catch (InvalidUserFieldException $e) {
                dd($e);
            }
    
            return response()->json($cognitoRegistered);
        }
    }
    
    opened by ionut-tanasa 6
  • Get Access/refresh tokens

    Get Access/refresh tokens

    I'm trying to use the library to create a simple portal around a lambda API thats authenticated using Cognito access tokens, so when a user logs in I need to be able to retrieve the access token associated with the cognito reponse you receive in the session guard hasValidCredentials method.

    Would you be open to a pull request that made this data available either by:

    1. Firing an event so the developer could do what they wanted with the response or
    2. Adding a config value to auto save this to the session

    Let me know what you think

    enhancement 
    opened by ryanmitchell 5
  • Identity Providers

    Identity Providers

    Using this package are you able to use different identity providers (Google, Apple)? I might be blind but I'm not seeing anything in the docs.

    Best Regards, Jovan

    question 
    opened by jstojiljkovic 4
  • No Token Exception

    No Token Exception

    Hey guys, I am trying to build a simple login currently. The login is based on your demo application but I always get the error "No Token Exception", Unauthorized Request... I don't know what I am doing wrong though. The registration works just fine without any errors but the login works only if I don't use the middleware or try to get the Cognito user instead of the db user for example:

    Route::get('/home', function (AwsCognito $cognito) {
        ddd($cognito->user());
        return view('index');
    });
    

    or

    Route::middleware('aws-cognito')->get('/home', function () {
        //ddd($cognito->user());
        return view('index');
    });
    

    Cognito Config is unedited on my profile is a repository called finance_aws which can be used to rebuild my application as long as you add your .env file. Here's my code:

    User.php:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Models\User;
    use Ellaisys\Cognito\Auth\AuthenticatesUsers;
    use Ellaisys\Cognito\Auth\RegistersUsers;
    use Ellaisys\Cognito\AwsCognitoClient;
    use Illuminate\Contracts\Foundation\Application;
    use Illuminate\Http\JsonResponse;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;
    use Illuminate\Routing\Redirector;
    
    class UserController extends Controller
    {
        use RegistersUsers, AuthenticatesUsers;
    
        public function register(Request $request, AwsCognitoClient $client): Application|RedirectResponse|Redirector|JsonResponse
        {
            $collection = collect($request->all());
            $data = $collection->only(['email', 'username']);
    
            try {
                if ($this->createCognitoUser($data)) {
                    $user = new User($collection->toArray());
                    if(!$user->save()) {
                        $this->delete($collection->get('username'), $client);
                    }
    
                    return redirect(route('login'));
                }
            } catch (\Exception $e) {
                return response()->json(['code' => $e->getCode(), 'msg' => $e->getMessage()]);
            }
    
            return response()->json(['status' => 'error']);
        }
    
        public function delete(String $username, AwsCognitoClient $client) {
            $client->deleteUser($username);
            if(User::find($username)->delete()) return response()->json(['success' => true]);
            else response()->json(['success' => false]);
        }
    
        public function getPrivateInfo(String $username, AwsCognitoClient $client) {
            return $client->getUser($username);
        }
    }
    

    Kernel.php:

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'aws-cognito' => \Ellaisys\Cognito\Http\Middleware\AwsCognitoAuthenticate::class
    ];
    

    config/app.php:

    'providers' => [
    
        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
    
        /*
         * Package Service Providers...
         */
    
        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        Barryvdh\Debugbar\ServiceProvider::class,
        Aws\Laravel\AwsServiceProvider::class,
        Ellaisys\Cognito\Providers\AwsCognitoServiceProvider::class,
    ],
    
    'aliases' => [
    
        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'Date' => Illuminate\Support\Facades\Date::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Http' => Illuminate\Support\Facades\Http::class,
        'Js' => Illuminate\Support\Js::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'RateLimiter' => Illuminate\Support\Facades\RateLimiter::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        // 'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'Str' => Illuminate\Support\Str::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
        'Debugbar' => Barryvdh\Debugbar\Facades\Debugbar::class,
        'AWS' => Aws\Laravel\AwsFacade::class,
    ],
    

    LoginController:

    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use App\Http\Controllers\Controller;
    use App\Providers\RouteServiceProvider;
    
    //use Illuminate\Foundation\Auth\AuthenticatesUsers; //Removed for AWS Cognito
    use Ellaisys\Cognito\Auth\AuthenticatesUsers;
    use Illuminate\Contracts\Foundation\Application;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;
    use Illuminate\Routing\Redirector;
    
    //Added for AWS Cognito
    
    class LoginController extends Controller
    {
        /*
        |--------------------------------------------------------------------------
        | Login Controller
        |--------------------------------------------------------------------------
        |
        | This controller handles authenticating users for the application and
        | redirecting them to your home screen. The controller uses a trait
        | to conveniently provide its functionality to your applications.
        |
        */
    
        use AuthenticatesUsers;
    
        /**
         * Where to redirect users after login.
         *
         * @var string
         */
        protected $redirectTo = '/';
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('guest')->except('logout');
        }
    
    
        /**
         * Authenticate User
         *
         * @throws \HttpException
         *
         * @return mixed
         */
        public function login(\Illuminate\Http\Request $request)
        {
            try {
                //Convert request to collection
                $collection = collect($request->all());
    
                //Authenticate with Cognito Package Trait (with 'web' as the auth guard)
                if ($response = $this->attemptLogin($collection, 'web')) {
                    if ($response===true) {
                        $request->session()->regenerate();
    
                        return redirect(route('home'))->with('success', true);
                    } else if ($response===false) {
                        // If the login attempt was unsuccessful you may increment the number of attempts
                        // to login and redirect the user back to the login form. Of course, when this
                        // user surpasses their maximum number of attempts they will get locked out.
                        //
                        //$this->incrementLoginAttempts($request);
                        //
                        //$this->sendFailedLoginResponse($collection, null);
                    } else {
                        return $response;
                    } //End if
                } //End if
            } catch(Exception $e) {
                Log::error($e->getMessage());
                return $response->back()->withInput($request);
            } //Try-catch ends
    
        } //Function ends
    
        public function logout(Request $request): Redirector|Application|RedirectResponse
        {
            auth()->guard('web')->logout();
            if($request->getSession()->invalidate()) {
                return redirect(route('app.index'))->with('success', true);
            } else {
                return redirect(route('app.index'))->with('success', false);
            }
        }
    } //Class ends
    

    WebRoutes:

    <?php
    
    use App\Http\Controllers\AuthController;
    use App\Http\Controllers\UserController;
    use Ellaisys\Cognito\AwsCognito;
    use Ellaisys\Cognito\AwsCognitoClient;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Route;
    
    /*
    |--------------------------------------------------------------------------
    | Web Routes
    |--------------------------------------------------------------------------
    |
    | Here is where you can register web routes for your application. These
    | routes are loaded by the RouteServiceProvider within a group which
    | contains the "web" middleware group. Now create something great!
    |
    */
    Route::middleware('web')->get('/', function (AuthController $controller, AwsCognito $cognito, Request $request) {
        $request->session()->start();
        return view('index');
    })->name('app.index');
    
    Route::middleware('aws-cognito')->get('/home', function (AuthController $controller, AwsCognito $cognito) {
        //ddd($cognito->user());
        return view('index');
    });
    
    Route::middleware('aws-cognito')->get('/privacy', function () {
        return view('privacy');
    })->name('privacy');
    
    Route::middleware('aws-cognito')->get('/impress', function () {
        return view('impress');
    })->name('impress');
    
    Auth::routes();
    
    Route::get('/login', function () {
        return view('auth.login');
    })->name('login');
    
    Route::middleware('aws-cognito')->post('/password/change', function (Request $request, AuthController $controller) {
        return $controller->changePassword($request);
    })->name('cognito.action.change.password');
    
    Route::middleware('aws-cognito')->get('/password/change', function () {
        return view('auth.passwords.change');
    })->name('cognito.form.change.password');
    
    Route::get('/register', function () {
        return view('auth.register');
    })->name('user.register');
    
    Route::post('/register', function (Request $request, UserController $controller, AwsCognitoClient $client) {
        return $controller->register($request, $client);
    });
    

    ChangePasswordController:

    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use Illuminate\Http\Request;
    use App\Http\Controllers\Controller;
    use App\Providers\RouteServiceProvider;
    
    use Illuminate\Foundation\Validation\ValidatesRequests;
    use Illuminate\Support\Facades\Validator;
    
    use Ellaisys\Cognito\Auth\ChangePasswords as CognitoChangePasswords; //Added for AWS Cognito
    
    use Exception;
    use Illuminate\Validation\ValidationException;
    use Ellaisys\Cognito\Exceptions\AwsCognitoException;
    use Ellaisys\Cognito\Exceptions\NoLocalUserException;
    use Symfony\Component\HttpKernel\Exception\HttpException;
    use Aws\CognitoIdentityProvider\Exception\CognitoIdentityProviderException;
    
    class ChangePasswordController extends Controller
    {
        /*
        |--------------------------------------------------------------------------
        | Confirm Password Controller
        |--------------------------------------------------------------------------
        |
        | This controller is responsible for handling password confirmations and
        | uses a simple trait to include the behavior. You're free to explore
        | this trait and override any functions that require customization.
        |
        */
    
        use CognitoChangePasswords;
    
        /**
         * Where to redirect users when the intended url fails.
         *
         * @var string
         */
        protected $redirectTo = '/';
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('auth');
        }
    
    
        /**
         * Action to update the user password
         *
         * @param  \Illuminate\Http\Request  $request
         */
        public function actionChangePassword(Request $request)
        {
            try
            {
                //Validate request
                $validator = Validator::make($request->all(), [
                    'email'    => 'required|email',
                    'password'  => 'string|min:8',
                    'new_password' => 'required|confirmed|min:8',
                ]);
                $validator->validate();
    
                // Get Current User
                $userCurrent = auth()->guard('web')->user();
    
                if ($this->reset($request)) {
                    auth()->guard()->logout();
                    $request->session()->invalidate();
    
                    return redirect(route('login'))->with('success', true);
                } else {
                    return redirect()->back()
                        ->with('status', 'error')
                        ->with('message', 'Password updated failed');
                } //End if
            } catch(Exception $e) {
                $message = 'Error sending the reset mail.';
                if ($e instanceof ValidationException) {
                    $message = $e->errors();
                } else if ($e instanceof CognitoIdentityProviderException) {
                    $message = $e->getAwsErrorMessage();
                } else {
                    //Do nothing
                } //End if
    
                return redirect()->back()
                    ->with('status', 'error')
                    ->with('message', $message);
            } //Try-catch ends
        }
    }
    
    bug 
    opened by Atronix1902 4
  • InvalidTokenException is thrown occasionally when the app runs on aws

    InvalidTokenException is thrown occasionally when the app runs on aws

    Hello, I am using this package and works like a charm, however, sometimes it throws an InvalidTokenException, and if I am running the same request, everything works alright. This happens only when the application is running on aws lambda, while on linux this error doesn't occur.

    Does anyone have any idea why this would happen?

    opened by iturcanu 4
  • How to use `actingAs` in unit tests

    How to use `actingAs` in unit tests

    Hi,

    We have feature tests that send requests to the api on behalf of a user to make sure our controllers behave appropriately. We previously used the actingAs method now that we're using Cognito the validation is made on AWS side.

    Is there something that exists that could help me within this package or should I implement a mechanic to handle authentication with a real user?

    Thank you

    opened by nicholasc 4
  • InvalidSignatureException

    InvalidSignatureException

    Hi, Registration works fine but when I try to get login I am getting the below error. Can you please guide is there anything I am missing? { "status": "error", "message": { "headers": {}, "original": { "error": "InvalidSignatureException", "message": "InvalidSignatureException" }, "exception": null } }

    documentation enhancement 
    opened by rehans90 4
  • Get claim data for logged in user

    Get claim data for logged in user

    Im using the web driver and have all authentication etc set up (thanks for the library btw!)

    I'd like to check some custom attributes for the logged in user in middleware, to verify what they can and cant access in the system. I cant see any way of doing that - can you point me in the right directions?

    duplicate enhancement 
    opened by ryanmitchell 3
  • Call to a member function except() on array

    Call to a member function except() on array

    AuthenticateUser.php line 64 sends an (array) $credentials to CreateLocalUser

      $response = $this->createLocalUser($credentials, $keyPassword);
    

    and throw an error

      Call to a member function except() on array
    

    as on line 98 it's trying to remove password from it

    $credentials->except($keyPassword)

    bug 
    opened by danicsan 3
  • Implementing MFA

    Implementing MFA

    Discussed in https://github.com/ellaisys/aws-cognito/discussions/48

    Originally posted by gadget-man October 22, 2022 Hello! I've been looking to implement Cognito MFA (SMS) in my code. I've been previously using black-bits, but have just come across this repo. I can see that MFA was added in an earlier commit - however I can't see from the demo-app how it is implemented. Does anyone have any 'live' examples of how the login page of the demo app needs to be updated to catch SMS_MFA as the ChallengeName and allow the user to enter and submit the MFA code?

    Any pointers in the right direction would be much appreciated!

    documentation demo 
    opened by amitdhongde 0
  • Architectural change for the request for the Token Guard

    Architectural change for the request for the Token Guard

    I built a more like api based a laravel application. There are also some other api services which is built with serverless structure and using cognito authorizers. Since both of the services are being used in the mobile platforms two different token structure is needed. To make it mono structure, it is being requested from me to use same cogito token for authorization. I have read the implementation especially for Token system and following is my solution which I believe will work better. Especially the reason I suggest this solution is the fact that cognito mobil sdks do the most of the job easily in terms of login, registration and token refreshing vice versa.

    Solution The package already verify the token and claim the user. However, I believe if we can add a column to User's data named sub, we can easily match the user and return the user. That's how we can use the powerful features of the User model. Example Token Verification Payload

    {
      "sub": "aaaaaaaa-bbbb-cccc-dddd-example",
      "aud": "xxxxxxxxxxxxexample",
      "email_verified": true,
      "token_use": "id",
      "auth_time": 1500009400,
      "iss": "https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-2_example",
      "cognito:username": "anaya",
      "exp": 1500013000,
      "given_name": "Anaya",
      "iat": 1500009400,
      "email": "[email protected]"
    }
    

    Additional context Since the program is already in production it is hard to make radical changes in the code. That's why what I am seeking for basically a cognito authorizer which I can match the verified user with already existing users using their sub. Why I am creating this issue is that I saw that this packages simply ignores sub and uses username since it is also unique. However, I think it is important to involve the sub which corresponds to id in our case.

    I also could not understand the match mechanism of the package. From the example code

                //Register User in cognito
                if ($cognitoRegistered=$this->createCognitoUser($data)) {
    
                    //If successful, create the user in local db
                    User::create($collection->only('name', 'email'));
                } //End if
    

    I understand that you are matching users using their email by default. To change it the keyUsername should be changed. Can we change it to phone_number for example. If yes how we can do it?

    class CognitoTokenGuard extends TokenGuard
    {
        /**
         * Username key
         * 
         * @var  \string  
         */
        protected $keyUsername;
    
       ...
    

    Appreciate your help and understanding.

    opened by Physicliar 2
  • Laravel 9 - Laravel Breeze support

    Laravel 9 - Laravel Breeze support

    Hi guys,

    First of all, thanks for your hard work.

    Do you think there are any chance to have this working on Laravel 9 and Laravel Breeze/Laravel Jetstream packages?

    Thanks.

    enhancement 
    opened by grudge61 3
  • Revert

    Revert "Update AuthenticatesUsers.php"

    Hi! I see you has reverts all changes from my pull request. Also, I see that you has merged all my forked repository along with unnecessary changes. But I can send you clean pull request treesome only necessary commits.

    enhancement 
    opened by sunnydesign 4
Releases(v1.0.10)
Owner
EllaiSys
EllaiSys is a young technology & managed services firm with focus on #ProductDevelopment #Cloud #BigData, #Mobility, #RPA & #DevOps.
EllaiSys
A Laravel 5+ (and 4) service provider for the AWS SDK for PHP

AWS Service Provider for Laravel 5/6/7/8 This is a simple Laravel service provider for making it easy to include the official AWS SDK for PHP in your

Amazon Web Services 1.5k Dec 28, 2022
Shopware PHP SDK is a simple SDK implementation of Shopware 6 APIs

Shopware PHP SDK is a simple SDK implementation of Shopware 6 APIs. It helps to access the API in an object-oriented way.

Thuong Le 77 Dec 19, 2022
PHP library/SDK for Crypto APIs 2.0 using Guzzle version 7

cryptoapis/sdk-guzzle7 Crypto APIs 2.0 is a complex and innovative infrastructure layer that radically simplifies the development of any Blockchain an

Crypto APIs 3 Oct 21, 2022
The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructure and leverage the power of 1Password Secrets Automation

1Password Connect PHP SDK The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructu

Michelangelo van Dam 12 Dec 26, 2022
Facebook SDK for PHP (v6) - allows you to access the Facebook Platform from your PHP app

Facebook SDK for PHP (v6) This repository contains the open source PHP SDK that allows you to access the Facebook Platform from your PHP app. Installa

null 0 Aug 10, 2022
Fully unit tested Facebook SDK v5 integration for Laravel & Lumen

Laravel Facebook SDK A fully unit-tested package for easily integrating the Facebook SDK v5 into Laravel and Lumen 5.0, 5.1, 5.2, & 5.3. This is packa

Sammy Kaye Powers 697 Nov 6, 2022
Paynow SDK Laravel integration

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Alfred Tanaka Kudiwahove 2 Sep 20, 2021
Unofficial Firebase Admin SDK for PHP

Firebase Admin PHP SDK Table of Contents Overview Installation Documentation Support License Overview Firebase provides the tools and infrastructure y

kreait 1.9k Jan 3, 2023
Notion PHP SDK

Notion PHP SDK This is an unofficial PHP SDK for the new public Notion API. It's work in progress as we didn't get the change to be included to the pr

Codecycler 43 Nov 29, 2022
爱发电非官方简易 PHP SDK

afdian-php-sdk 爱发电非官方简易 PHP SDK by Akkariin 这是一个简单的 SDK,可以用于查询爱发电的订单和赞助者信息 Installation 将项目 clone 到本地即可 git clone https://github.com/ZeroDream-CN/afdi

ZeroDream-CN 17 Nov 7, 2022
PHP SDK to interact with the Casper Network nodes via RPC

casper-php-sdk PHP SDK to interact with Casper Network nodes via RPC Install composer require make-software/casper-php-sdk Examples RPC Client: $node

MAKE Technology LLC 7 May 8, 2022
A complete Notion SDK for PHP developers.

notion-sdk-php A complete Notion SDK for PHP developers. Installation composer require mariosimao/notion-php Getting started A Notion token will be n

Mario Simão 77 Nov 29, 2022
SDK of the LINE Login API for PHP

LINE Login for PHP SDK of the LINE Login API for PHP Documentation See the official API documentation for more information. Installation Use the packa

null 4 Sep 15, 2022
PHP SDK - Flexie CRM fiskalizimi solution

PHP SDK - Flexie CRM fiskalizimi solution Fiskalizimi PHP SDK allows you to talk and generate your e-invoices programmatically from your own solution

Flexie CRM 3 Dec 30, 2021
PHP Digital Green Certificate SDK

Digital Green Certificate SDK PHP Indice Contesto Installazione Uso Licenza Dettaglio licenza Contesto Attenzione, questo repository è derivato dalle

null 13 Jun 20, 2022
Esse SDK em PHP foi desenvolvido no intuito de tornar mais prático a integração com nossa API.

Sobre Beedoo SDK Acessar documentação completa da Beedoo API. A API é organizada seguindo a arquitetura REST, boas práticas, convenções e padrões como

Beedoo Edtech 5 Dec 2, 2021
A PHP SDK for accessing the OpenAI GPT-3 API

OpenAI GPT-3 Api Client in PHP Installation You can install the package via composer: composer require orhanerday/open-ai Usage use Orhanerday\OpenAi\

Orhan erday 462 Jan 2, 2023
The Facebook SDK for PHP provides a native interface to the Graph API and Facebook Login

Facebook SDK for PHP (v5) This repository contains the open source PHP SDK that allows you to access the Facebook Platform from your PHP app. Installa

Meta Archive 3.1k Dec 30, 2022
PHP SDK for the Sellix Developers API (developers.sellix.io)

PHP SDK for the Sellix Developers API (developers.sellix.io). Quickly get started and create products, payments and more using PHP.

Sellix 7 Nov 23, 2022