Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requested Grant type authorization code with curl #1458

Open
viniribeirossa opened this issue Nov 3, 2024 · 1 comment
Open

Requested Grant type authorization code with curl #1458

viniribeirossa opened this issue Nov 3, 2024 · 1 comment
Labels

Comments

@viniribeirossa
Copy link

viniribeirossa commented Nov 3, 2024

I implemented and it is working correctly in my project the Grant type password to login with email and password

Now, I have activated the Grant type authorization code to login/register with Google using the library https://github.com/thephpleague/oauth2-google
I'm testing with curl and it gives this error

curl -X POST http://localhost:9000/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=cdc-client" \
  -d "client_secret=d9e640ab946ef196003f5972913c570d918bef8e480daa206a10227b87b02cd0" \
  -d "redirect_uri=http://localhost:9000/auth/google/callback" \
  -d "code=4/0AVG7fiT52c1QiaVVJjWdPb7A-izfVsZ4cRfJEaTr8MzY_9AKJXY40XU6A204xOMy2gESvg"

The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.%             ➜  ~

AuthService class method


public function obtainAccessTokenByAuthCode(UserEntity $userEntity, string $authCode, Request $request, Response $response): Response
	{
		// Obtenha o client_id e secret do cliente local
		$clientEntity = $this->clientRepository->getFirstClientEntity();
		$this->logger->info("Obtendo client_entity para requisição de token", [
			'client_id' => $clientEntity->getIdentifier(),
			'client_secret' => $clientEntity->getSecret()
		]);

		// Obtenha os escopos finalizados do ScopeRepository
		$scopes = $this->scopeRepository->getScopesByUserId($userEntity->getIdentifier());
		$scopeIdentifiers = array_map(fn($scope) => $scope->getIdentifier(), $scopes);
		$this->logger->info("Escopos obtidos para o usuário", [
			'user_id' => $userEntity->getIdentifier(),
			'scopes' => $scopeIdentifiers
		]);

		// Dados para requisição de token
		$requestData = [
			'grant_type' => 'authorization_code',
			'client_id' => $clientEntity->getIdentifier(),
			'client_secret' => $clientEntity->getSecret(),
			'redirect_uri' => $_ENV['GOOGLE_REDIRECT_URI'],
			'code' => $authCode,
			'scope' => implode(' ', $scopeIdentifiers)
		];

		$this->logger->info("Dados preparados para solicitação de token", [
			'request_data' => $requestData,
			'auth_server_url' => $this->authServerUrl . '/oauth/token'
		]);

		try {
			// Enviando a requisição para o servidor de autenticação
			$authResponse = $this->httpClient->post($this->authServerUrl . '/oauth/token', [
				'form_params' => $requestData
			]);

			$responseBody = (string) $authResponse->getBody();
			$this->logger->info("Resposta do servidor de autenticação recebida", [
				'status_code' => $authResponse->getStatusCode(),
				'response_body' => json_decode($responseBody, true)
			]);

			return $response->withHeader('Content-Type', 'application/json')
			->withStatus($authResponse->getStatusCode())
			->withBody($authResponse->getBody());

		} catch (\Exception $e) {
			$this->logger->error("Erro ao obter token de acesso", [
				'exception_message' => $e->getMessage(),
				'request_data' => $requestData
			]);

			return $this->jsonResponse($response, [
				'error' => 'token_request_failed',
				'message' => $e->getMessage()
			], 500);
		}
	}

GoogleProviderController class method

public function handleGoogleCallback(Request $request, Response $response): Response
	{
		$params = $request->getQueryParams();

		// Verificar estado para prevenir CSRF
		if (empty($params['state']) || ($params['state'] !== $_SESSION['oauth2state'])) {
			unset($_SESSION['oauth2state']);
			$this->logger->error('Estado inválido na autenticação com o Google');
			return $response->withStatus(400)->write('Estado inválido');
		}

		try {
			// 1. Obter o token de acesso do Google usando o código de autorização
			$accessToken = $this->googleProvider->getAccessToken('authorization_code', [
				'code' => $params['code']
			]);

			$idToken = $accessToken->getValues()['id_token'] ?? null;
			if (!$idToken) {
				$this->logger->error('id_token não encontrado na resposta do Google');
				throw new \Exception("id_token não encontrado.");
			}

			// 2. Validar e extrair o id_token
			$tokenInfo = $this->validateIdToken($idToken);
			if (empty($tokenInfo['email'])) {
				$this->logger->error('E-mail ausente nos dados do Google.', ['tokenInfo' => $tokenInfo]);
				throw new \Exception("E-mail ausente nos dados retornados pelo Google.");
			}

			// 3. Criar ou buscar usuário local
			$googleUserData = [
				'sub' => $tokenInfo['sub'],
				'email' => $tokenInfo['email'],
				'name' => $tokenInfo['name'],
				'picture' => $tokenInfo['picture'],
				'email_verified' => $tokenInfo['email_verified']
			];


			$this->logger->info('Dados do usuário recebidos do Google', ['googleUserData' => $googleUserData]);

			// Buscar ou criar usuário
			$userEntity = $this->findOrCreateUser($googleUserData);

			// Gerar token de acesso local
			$localAccessTokenResponse = $this->authService->obtainAccessTokenByAuthCode($userEntity, $params['code'], $request, $response);

			// Decodificar a resposta para verificar o token gerado
			$tokenData = json_decode((string) $localAccessTokenResponse->getBody(), true);

			if (!isset($tokenData['access_token'])) {
				$this->logger->error("Falha ao gerar token de acesso local após o login com o Google");
				$response->getBody()->write('Erro interno de autenticação');
				return $response->withStatus(500);
			}

			// Configurar o cookie com o token de acesso
			setcookie('access_token', $tokenData['access_token'], [
				'expires' => time() + 3600,
				'path' => '/',
				'secure' => false,
				'httponly' => true,
				'samesite' => 'Strict'
			]);

			// Redirecionar de acordo com o papel do usuário
			$username = $userEntity->getUsername();
			$redirectUrl = match ($userEntity->getRole()) {
				'admin' => '/admin/',
				'moderator' => '/moderator/',
				'user' => '/u/@' . $username,
				'developer' => '/developer/',
				default => '/u/@' . $username,
				};

				$this->logger->info('Usuário autenticado com sucesso e redirecionado', [
					'user_id' => $userEntity->getUserId(),
					'redirect_url' => $redirectUrl
				]);

				return $response->withHeader('Location', $redirectUrl)->withStatus(302);

			} catch (\Exception $e) {
				$this->logger->error('Erro ao processar callback do Google: ' . $e->getMessage());
				return $response->withStatus(500)->write('Erro durante a autenticação com o Google.');
			}
		}

Routes

$app->get('/auth/google', GoogleProviderController::class . ':redirectToGoogle');
$app->get('/auth/google/callback', GoogleProviderController::class . ':handleGoogleCallback');


$app->post('/oauth/token', function (Request $request, Response $response) use ($server) {
		try {
			return $server->respondToAccessTokenRequest($request, $response);
		} catch (OAuthServerException $exception) {
			return $exception->generateHttpResponse($response);
		} catch (\Exception $exception) {
			// Correção para criação do Stream com recurso
			$body = new Stream(fopen('php://temp', 'r+'));
			$body->write($exception->getMessage());
			return $response->withStatus(500)->withBody($body);
		}
	});

My problem is basically this, I receive the information from Google and it is valid, however, when switching to a local token it does not generate

@Sephster
Copy link
Member

There are quite a few reasons why an invalidRequest exception is thrown on the auth code grant so it is hard for me to tell from the information provided. The exceptions also issue hints which will give more information about what field is missing or invalid. Use the getHint() method on the exception to get more details about where this is going wrong. Hope this helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants