/** * Returns the POST response * * @param \PSX\Record\RecordInterface $record * @return array|\PSX\Record\RecordInterface */ protected function doPost($record) { $responseType = $record->responseType; $clientId = $record->clientId; $redirectUri = $record->redirectUri; $scope = $record->scope; $state = $record->state; // response type if (!in_array($responseType, ['code', 'token'])) { throw new StatusCode\BadRequestException('Invalid response type'); } // client id $app = $this->appService->getByAppKey($clientId); if (empty($app)) { throw new StatusCode\BadRequestException('Unknown client id'); } // redirect uri if (!empty($redirectUri)) { $redirectUri = new Uri($redirectUri); if (!$redirectUri->isAbsolute()) { throw new StatusCode\BadRequestException('Redirect uri must be an absolute url'); } if (!in_array($redirectUri->getScheme(), ['http', 'https'])) { throw new StatusCode\BadRequestException('Invalid redirect uri scheme'); } $url = $app['url']; if (!empty($url)) { $url = new Url($url); if ($url->getHost() != $redirectUri->getHost()) { throw new StatusCode\BadRequestException('Redirect uri must have the same host as the app url'); } } else { throw new StatusCode\BadRequestException('App has no url configured'); } } else { $redirectUri = null; } // scopes $scopes = $this->scopeService->getValidScopes($app['id'], $this->userId, $scope, ['backend']); if (empty($scopes)) { throw new StatusCode\BadRequestException('No valid scopes provided'); } // save the decision of the user. We save the decision so that it is // possible for the user to revoke the access later on $this->saveUserDecision($app['id'], $record->allow); if ($record->allow) { if ($responseType == 'token') { // check whether implicit grant is allowed if ($this->config['fusio_grant_implicit'] !== true) { throw new StatusCode\BadRequestException('Token response type is not supported'); } // redirect uri is required for token types if (!$redirectUri instanceof Uri) { throw new StatusCode\BadRequestException('Redirect uri is required'); } // generate access token $accessToken = $this->appService->generateAccessToken($app['id'], $this->userId, $scopes, isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1', new \DateInterval($this->config->get('fusio_expire_implicit'))); $parameters = $accessToken->getProperties(); if (!empty($state)) { $parameters['state'] = $state; } $redirectUri = $redirectUri->withFragment(http_build_query($parameters, '', '&'))->toString(); return ['type' => 'token', 'token' => $accessToken, 'redirectUri' => $redirectUri]; } else { // generate code which can be later exchanged by the app with an // access token $code = $this->appCodeService->generateCode($app['id'], $this->userId, $redirectUri, $scopes); if ($redirectUri instanceof Uri) { $parameters = array(); $parameters['code'] = $code; $parameters['state'] = $state; $redirectUri = $redirectUri->withParameters($parameters)->toString(); } else { $redirectUri = '#'; } return ['type' => 'code', 'code' => $code, 'redirectUri' => $redirectUri]; } } else { // @TODO delete all previously issued tokens for this app? if ($redirectUri instanceof Uri) { $parameters = array(); $parameters['error'] = 'access_denied'; if (!empty($state)) { $parameters['state'] = $state; } if ($responseType == 'token') { $redirectUri = $redirectUri->withFragment(http_build_query($parameters, '', '&'))->toString(); } else { $redirectUri = $redirectUri->withParameters($parameters)->toString(); } } else { $redirectUri = '#'; } return ['type' => 'access_denied', 'redirectUri' => $redirectUri]; } }