ellaisys / aws-cognito

AWS Cognito package (with MFA Feature) using the AWS SDK for PHP/Laravel
https://ellaisys.github.io/aws-cognito/
MIT License
110 stars 41 forks source link

OAuth2 Token as Token #40

Closed Atronix1902 closed 2 years ago

Atronix1902 commented 2 years ago

hey it's me again.

I have a frontend that generates an oauth2 token via the hosted UI of Cognito. How can I use it in the backend to authenticate the user, when I try it via the normal API guard which uses the Cognito-token driver? Every time I try to send a request the backend sends

{
    "message": "Invalid Authentication Token"
}

back.

It's working when I use Cognito to generate a bearer token, but I need to use OAuth2. Frontend and Backend are using the same ClientID and Secret. What am I doing wrong?

Route:

Route::middleware('aws-cognito')->get('/user',  function () {
    return \auth()->guard('api')->user();
});

Guards:

'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',
    ],
],
Atronix1902 commented 2 years ago

Ideal would be to use the id-token to authenticate

Edit: would be interesting to know if it's possible to, but just wrote an own middleware whicht is used instead of aws-cognito to authorize by Hosted-UI token. It's a bit hacky but for people who need something similar i'm gonna post it here:

<?php

namespace App\Http\Middleware;

use App\Models\User;
use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient;
use Aws\Exception\AwsException;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class AwsOauth
{
    /**
     * Handle an incoming request.
     *
     * @param Request $request
     * @param Closure(Request): (Response|RedirectResponse) $next
     * @return JsonResponse
     */
    public function handle(Request $request, Closure $next, ...$guards)
    {
        $cognito = new CognitoIdentityProviderClient([
            'credentials'   => [
                'key'       => env('AWS_ACCESS_KEY_ID'),
                'secret'    => env('AWS_SECRET_ACCESS_KEY')
            ],
            'version'       => env('AWS_COGNITO_VERSION'),
            'region'        => env('AWS_COGNITO_REGION'),
            'userpool'      => env('AWS_COGNITO_USER_POOL_ID')
        ]);
        try {
            $data = $cognito->getUser([
                'AccessToken' => str_replace('Bearer ', '', $request->header('Authorization')),
            ]);
            $username = $data['Username'];
            $user = User::where(['username' => $username])->first();

            // Create User if not found in database (SSO)
            if(!($user instanceof User)) {
                $user = new User();
                $user->username = $username;
                $user->sub = collect($data['UserAttributes'])->firstWhere('Name', '=', 'sub')['Value'];
                $user->email = collect($data['UserAttributes'])->firstWhere('Name', '=', 'email')['Value'];
                $user->save();
            }
        } catch (AwsException $exception) {
            return \response()->json([
                'message'   => $exception->getAwsErrorMessage()
            ])->setStatusCode(401);
        }

        auth()->setUser($user);
        return $next($request);
    }
}

For now I'm going to close this issue but would like to know if you have another solution.

amitdhongde commented 2 years ago

Hi Atronix,

This library does not use an existing token and validate the user. Instead with this library, you can generate Cognito tokens that are stored in the storage configuration path (file, dynamodb, etc).

This library allows you to build your own frontend and manage the authentication using Cognito. There is no need to have any Hosted UI while using this.