I succeed to fetch the Linkedin users Data, Create a User object and inject User details in it, Persist it into the DB, and even Generate a JWT token:
$jwtToken = $this->jwtManager->create($userEntity);
But it seems that the token is no "active"
{
"code": 401,
"message": "Invalid credentials."
}
When I use directly the /api/login_check from Security it works:
{
"message": "Welcome to your new controller!",
"path": "src/Controller/DashboardController.php"
}
I also tried this: return $security->login($userEntity, 'json_login', 'login'); Where "login" is the firewall used by JWT and 'json_login' the authenticator(See security). https://symfony.com/doc/current/security.html#login-programmatically
I also tried this with no success: return $authenticationSuccessHandler->handleAuthenticationSuccess($user); https://github.com/lexik/LexikJWTAuthenticationBundle/issues/1113
$userEntity is containing the right User and the JWT Token is containing all the details.
Now the JSon answer is containing the JWT Token, but is invalid when I put it in the Bearer Token.
Can you please help me? Thank you!
** Bundles Installed:**
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/doctrine-bundle": "^2.10",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.16",
"friendsofsymfony/rest-bundle": "^3.6",
"jms/serializer-bundle": "^5.3",
"league/oauth2-linkedin": "^5.1",
"lexik/jwt-authentication-bundle": "*",
"symfony/console": "6.3.*",
"symfony/dotenv": "6.3.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.3.*",
"symfony/runtime": "6.3.*",
"symfony/yaml": "6.3.*"
Security:
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
App\Entity\User: 'auto'
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: 'auto'
cost: 15
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
jwt: ~
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/api/register, roles: PUBLIC_ACCESS }
- { path: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api/auth/linkedin, roles: PUBLIC_ACCESS }
- { path: ^/api/li-callback, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
Controler:
<?php
// src/Controller/LinkedinAuthController.php
namespace App\Controller;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use App\Service\LinkedinAuthService;
use App\Service\UserManager;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use League\OAuth2\Client\Provider\Linkedin;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Bundle\SecurityBundle\Security;
class LinkedinAuthController extends AbstractController
{
private $linkedinAuthService;
private $entityManager;
private $jwtManager;
private $authenticationSuccessHandler;
public function __construct(LinkedinAuthService $linkedinAuthService, EntityManagerInterface $entityManager, JWTTokenManagerInterface $jwtManager)
{
$this->linkedinAuthService = $linkedinAuthService;
$this->entityManager = $entityManager;
$this->jwtManager = $jwtManager;
}
/**
* @Route("/api/auth/linkedin", name="api_auth_linkedin")
*/
public function redirectToLinkedin(): Response
// public function redirectToLinkedin(): JsonResponse
{...}
/**
* @Route("/api/li-callback", name="api_linkedin_callback")
*/
public function linkedinCallback(Request $request, Security $security): JsonResponse
{
session_start();
if (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
return new JsonResponse(['error' => 'Invalid state'], 401);
}
try {
$linkedinUser = $this->linkedinAuthService->getUserData($_GET['code']);
$userEntity = $this->findOrCreateUser($linkedinUser);
// Generate JWT Token
// $jwtToken = $this->jwtManager->create($userEntity);
// you can also log in on a different firewall
return $security->login($userEntity, 'json_login', 'login');
} catch (IdentityProviderException $e) {
return new JsonResponse(['error' => 'Authentication failed: '.$e->getMessage()], 401);
}
}