This commit is contained in:
Graham Campbell
2014-11-08 18:26:12 +00:00
parent 30162c8899
commit 4c1cd04a24
61 changed files with 430 additions and 503 deletions

View File

@@ -2,14 +2,12 @@
namespace RelationalExample\Storage;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\AbstractTokenEntity;
use League\OAuth2\Server\Entity\AccessTokenEntity;
use League\OAuth2\Server\Entity\ScopeEntity;
use League\OAuth2\Server\Storage\AccessTokenInterface;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Entity\AccessTokenEntity;
use League\OAuth2\Server\Entity\AbstractTokenEntity;
use League\OAuth2\Server\Entity\RefreshTokenEntity;
use League\OAuth2\Server\Entity\ScopeEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
class AccessTokenStorage extends Adapter implements AccessTokenInterface
{
@@ -50,7 +48,7 @@ class AccessTokenStorage extends Adapter implements AccessTokenInterface
foreach ($result as $row) {
$scope = (new ScopeEntity($this->server))->hydrate([
'id' => $row['id'],
'description' => $row['description']
'description' => $row['description'],
]);
$response[] = $scope;
}
@@ -68,7 +66,7 @@ class AccessTokenStorage extends Adapter implements AccessTokenInterface
->insert([
'access_token' => $token,
'session_id' => $sessionId,
'expire_time' => $expireTime
'expire_time' => $expireTime,
]);
}
@@ -80,7 +78,7 @@ class AccessTokenStorage extends Adapter implements AccessTokenInterface
Capsule::table('oauth_access_token_scopes')
->insert([
'access_token' => $token->getId(),
'scope' => $scope->getId()
'scope' => $scope->getId(),
]);
}

View File

@@ -2,12 +2,11 @@
namespace RelationalExample\Storage;
use League\OAuth2\Server\Storage\AuthCodeInterface;
use League\OAuth2\Server\Storage\Adapter;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\AuthCodeEntity;
use League\OAuth2\Server\Entity\ScopeEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Storage\AuthCodeInterface;
class AuthCodeStorage extends Adapter implements AuthCodeInterface
{
@@ -25,6 +24,7 @@ class AuthCodeStorage extends Adapter implements AuthCodeInterface
$token = new AuthCodeEntity($this->server);
$token->setId($result[0]['auth_code']);
$token->setRedirectUri($result[0]['client_redirect_uri']);
return $token;
}
@@ -38,7 +38,7 @@ class AuthCodeStorage extends Adapter implements AuthCodeInterface
'auth_code' => $token,
'client_redirect_uri' => $redirectUri,
'session_id' => $sessionId,
'expire_time' => $expireTime
'expire_time' => $expireTime,
]);
}
@@ -59,7 +59,7 @@ class AuthCodeStorage extends Adapter implements AuthCodeInterface
foreach ($result as $row) {
$scope = (new ScopeEntity($this->server))->hydrate([
'id' => $row['id'],
'description' => $row['description']
'description' => $row['description'],
]);
$response[] = $scope;
}
@@ -76,7 +76,7 @@ class AuthCodeStorage extends Adapter implements AuthCodeInterface
Capsule::table('oauth_auth_code_scopes')
->insert([
'auth_code' => $token->getId(),
'scope' => $scope->getId()
'scope' => $scope->getId(),
]);
}

View File

@@ -2,12 +2,11 @@
namespace RelationalExample\Storage;
use League\OAuth2\Server\Storage\ClientInterface;
use League\OAuth2\Server\Storage\Adapter;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\ClientEntity;
use League\OAuth2\Server\Entity\SessionEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Storage\ClientInterface;
class ClientStorage extends Adapter implements ClientInterface
{
@@ -36,7 +35,7 @@ class ClientStorage extends Adapter implements ClientInterface
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $result[0]['id'],
'name' => $result[0]['name']
'name' => $result[0]['name'],
]);
return $client;
@@ -60,7 +59,7 @@ class ClientStorage extends Adapter implements ClientInterface
$client = new ClientEntity($this->server);
$client->hydrate([
'id' => $result[0]['id'],
'name' => $result[0]['name']
'name' => $result[0]['name'],
]);
return $client;

View File

@@ -2,11 +2,10 @@
namespace RelationalExample\Storage;
use League\OAuth2\Server\Storage\RefreshTokenInterface;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Entity\RefreshTokenEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\RefreshTokenEntity;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Storage\RefreshTokenInterface;
class RefreshTokenStorage extends Adapter implements RefreshTokenInterface
{
@@ -40,7 +39,7 @@ class RefreshTokenStorage extends Adapter implements RefreshTokenInterface
->insert([
'refresh_token' => $token,
'access_token' => $accessToken,
'expire_time' => $expireTime
'expire_time' => $expireTime,
]);
}
@@ -53,5 +52,4 @@ class RefreshTokenStorage extends Adapter implements RefreshTokenInterface
->where('refresh_token', $token->getId())
->delete();
}
}

View File

@@ -2,11 +2,10 @@
namespace RelationalExample\Storage;
use League\OAuth2\Server\Storage\ScopeInterface;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Entity\ScopeEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\ScopeEntity;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Storage\ScopeInterface;
class ScopeStorage extends Adapter implements ScopeInterface
{
@@ -25,7 +24,7 @@ class ScopeStorage extends Adapter implements ScopeInterface
return (new ScopeEntity($this->server))->hydrate([
'id' => $result[0]['id'],
'description' => $result[0]['description']
'description' => $result[0]['description'],
]);
}
}

View File

@@ -2,14 +2,13 @@
namespace RelationalExample\Storage;
use League\OAuth2\Server\Storage\SessionInterface;
use League\OAuth2\Server\Storage\Adapter;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\AccessTokenEntity;
use League\OAuth2\Server\Entity\AuthCodeEntity;
use League\OAuth2\Server\Entity\SessionEntity;
use League\OAuth2\Server\Entity\ScopeEntity;
use Illuminate\Database\Capsule\Manager as Capsule;
use League\OAuth2\Server\Entity\SessionEntity;
use League\OAuth2\Server\Storage\Adapter;
use League\OAuth2\Server\Storage\SessionInterface;
class SessionStorage extends Adapter implements SessionInterface
{
@@ -74,7 +73,7 @@ class SessionStorage extends Adapter implements SessionInterface
foreach ($result as $scope) {
$scopes[] = (new ScopeEntity($this->server))->hydrate([
'id' => $scope['id'],
'description' => $scope['description']
'description' => $scope['description'],
]);
}
@@ -90,7 +89,7 @@ class SessionStorage extends Adapter implements SessionInterface
->insertGetId([
'owner_type' => $ownerType,
'owner_id' => $ownerId,
'client_id' => $clientId
'client_id' => $clientId,
]);
return $id;
@@ -104,7 +103,7 @@ class SessionStorage extends Adapter implements SessionInterface
Capsule::table('oauth_session_scopes')
->insert([
'session_id' => $session->getId(),
'scope' => $scope->getId()
'scope' => $scope->getId(),
]);
}
}

View File

@@ -1,19 +1,17 @@
<?php
use \Orno\Http\Request;
use \Orno\Http\Response;
use \Orno\Http\JsonResponse;
use \Orno\Http\Exception\NotFoundException;
use \League\OAuth2\Server\ResourceServer;
use \RelationalExample\Storage;
use \RelationalExample\Model;
use Illuminate\Database\Capsule\Manager as Capsule;
use \League\Event\Emitter;
use League\OAuth2\Server\ResourceServer;
use Orno\Http\Exception\NotFoundException;
use Orno\Http\Request;
use Orno\Http\Response;
use RelationalExample\Model;
use RelationalExample\Storage;
include __DIR__.'/vendor/autoload.php';
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
// Set up the OAuth 2.0 resource server
@@ -30,8 +28,8 @@ $server = new ResourceServer(
);
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
// GET /tokeninfo
$router->get('/tokeninfo', function (Request $request) use ($server) {
@@ -41,7 +39,7 @@ $router->get('/tokeninfo', function (Request $request) use ($server) {
'owner_type' => $server->getOwnerType(),
'access_token' => $server->getAccessToken(),
'client_id' => $server->getClientId(),
'scopes' => $server->getScopes()
'scopes' => $server->getScopes(),
];
return new Response(json_encode($token));
@@ -58,7 +56,7 @@ $router->get('/users', function (Request $request) use ($server) {
foreach ($results as $result) {
$user = [
'username' => $result['username'],
'name' => $result['name']
'name' => $result['name'],
];
if ($server->hasScope('email')) {
@@ -86,7 +84,7 @@ $router->get('/users/{username}', function (Request $request, $args) use ($serve
$user = [
'username' => $result[0]['username'],
'name' => $result[0]['name']
'name' => $result[0]['name'],
];
if ($server->hasScope('email')) {
@@ -103,7 +101,6 @@ $router->get('/users/{username}', function (Request $request, $args) use ($serve
$dispatcher = $router->getDispatcher();
try {
// Check that access token is present
$server->isValidRequest(false);
@@ -112,34 +109,25 @@ try {
$request->getMethod(),
$request->getPathInfo()
);
} catch (\Orno\Http\Exception $e) {
// A failed response
$response = $e->getJsonResponse();
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
$response = new Response(json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]), $e->httpStatusCode);
foreach ($e->getHttpHeaders() as $header) {
$response->headers($header);
}
} catch (\Exception $e) {
$response = new Orno\Http\Response;
$response = new Orno\Http\Response();
$response->setStatusCode(500);
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
} finally {
// Return the response
$response->headers->set('Content-type', 'application/json');
$response->send();
}

View File

@@ -1,29 +1,24 @@
<?php
use \Orno\Http\Request;
use \Orno\Http\Response;
use \Orno\Http\JsonResponse;
use \Orno\Http\Exception\NotFoundException;
use \League\OAuth2\Server\ResourceServer;
use \RelationalExample\Storage;
use \RelationalExample\Model;
use Illuminate\Database\Capsule\Manager as Capsule;
use \League\Event\Emitter;
use Orno\Http\Request;
use Orno\Http\Response;
use RelationalExample\Storage;
include __DIR__.'/vendor/autoload.php';
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
// Set up the OAuth 2.0 authorization server
$server = new \League\OAuth2\Server\AuthorizationServer;
$server->setSessionStorage(new Storage\SessionStorage);
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage);
$server->setClientStorage(new Storage\ClientStorage);
$server->setScopeStorage(new Storage\ScopeStorage);
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
$server = new \League\OAuth2\Server\AuthorizationServer();
$server->setSessionStorage(new Storage\SessionStorage());
$server->setAccessTokenStorage(new Storage\AccessTokenStorage());
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage());
$server->setClientStorage(new Storage\ClientStorage());
$server->setScopeStorage(new Storage\ScopeStorage());
$server->setAuthCodeStorage(new Storage\AuthCodeStorage());
$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant();
$server->addGrantType($authCodeGrant);
@@ -32,28 +27,24 @@ $refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
$server->addGrantType($refrehTokenGrant);
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
$router->get('/authorize', function (Request $request) use ($server) {
// First ensure the parameters in the query string are correct
try {
$authParams = $server->getGrantType('authorization_code')->checkAuthorizeParams();
} catch (\Exception $e) {
return new Response(
json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]),
$e->httpStatusCode,
$e->getHttpHeaders()
);
}
// Normally at this point you would show the user a sign-in screen and ask them to authorize the requested scopes
@@ -78,21 +69,18 @@ $router->get('/authorize', function (Request $request) use ($server) {
$router->post('/access_token', function (Request $request) use ($server) {
try {
$response = $server->issueAccessToken();
return new Response(json_encode($response), 200);
} catch (\Exception $e) {
return new Response(
json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]),
$e->httpStatusCode,
$e->getHttpHeaders()
);
}
});
@@ -100,40 +88,30 @@ $router->post('/access_token', function (Request $request) use ($server) {
$dispatcher = $router->getDispatcher();
try {
// A successful response
$response = $dispatcher->dispatch(
$request->getMethod(),
$request->getPathInfo()
);
} catch (\Orno\Http\Exception $e) {
// A failed response
$response = $e->getJsonResponse();
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
$response = new Response(json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]), $e->httpStatusCode);
foreach ($e->getHttpHeaders() as $header) {
$response->headers($header);
}
} catch (\Exception $e) {
$response = new Orno\Http\Response;
$response = new Orno\Http\Response();
$response->setStatusCode(500);
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
} finally {
// Return the response
$response->headers->set('Content-type', 'application/json');
$response->send();
}

View File

@@ -6,13 +6,13 @@ use Illuminate\Database\Capsule\Manager as Capsule;
include __DIR__.'/../vendor/autoload.php';
$capsule = new Capsule;
$capsule = new Capsule();
$capsule->addConnection([
'driver' => 'sqlite',
'database' => __DIR__.'/oauth2.sqlite3',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci'
'collation' => 'utf8_unicode_ci',
]);
$capsule->setAsGlobal();

View File

@@ -29,7 +29,7 @@ Capsule::table('users')->insert([
'password' => password_hash('whisky', PASSWORD_DEFAULT),
'name' => 'Alex Bilbie',
'email' => 'hello@alexbilbie.com',
'photo' => 'https://s.gravatar.com/avatar/14902eb1dac66b8458ebbb481d80f0a3'
'photo' => 'https://s.gravatar.com/avatar/14902eb1dac66b8458ebbb481d80f0a3',
]);
Capsule::table('users')->insert([
@@ -37,7 +37,7 @@ Capsule::table('users')->insert([
'password' => password_hash('cider', PASSWORD_DEFAULT),
'name' => 'Phil Sturgeon',
'email' => 'email@philsturgeon.co.uk',
'photo' => 'https://s.gravatar.com/avatar/14df293d6c5cd6f05996dfc606a6a951'
'photo' => 'https://s.gravatar.com/avatar/14df293d6c5cd6f05996dfc606a6a951',
]);
/******************************************************************************/
@@ -54,7 +54,7 @@ Capsule::schema()->create('oauth_clients', function ($table) {
Capsule::table('oauth_clients')->insert([
'id' => 'testclient',
'secret' => 'secret',
'name' => 'Test Client'
'name' => 'Test Client',
]);
/******************************************************************************/
@@ -69,7 +69,7 @@ Capsule::schema()->create('oauth_client_redirect_uris', function ($table) {
Capsule::table('oauth_client_redirect_uris')->insert([
'client_id' => 'testclient',
'redirect_uri' => 'http://example.com/redirect'
'redirect_uri' => 'http://example.com/redirect',
]);
/******************************************************************************/
@@ -84,17 +84,17 @@ Capsule::schema()->create('oauth_scopes', function ($table) {
Capsule::table('oauth_scopes')->insert([
'id' => 'basic',
'description' => 'Basic details about your account'
'description' => 'Basic details about your account',
]);
Capsule::table('oauth_scopes')->insert([
'id' => 'email',
'description' => 'Your email address'
'description' => 'Your email address',
]);
Capsule::table('oauth_scopes')->insert([
'id' => 'photo',
'description' => 'Your photo'
'description' => 'Your photo',
]);
/******************************************************************************/
@@ -114,19 +114,19 @@ Capsule::schema()->create('oauth_sessions', function ($table) {
Capsule::table('oauth_sessions')->insert([
'owner_type' => 'client',
'owner_id' => 'testclient',
'client_id' => 'testclient'
'client_id' => 'testclient',
]);
Capsule::table('oauth_sessions')->insert([
'owner_type' => 'user',
'owner_id' => '1',
'client_id' => 'testclient'
'client_id' => 'testclient',
]);
Capsule::table('oauth_sessions')->insert([
'owner_type' => 'user',
'owner_id' => '2',
'client_id' => 'testclient'
'client_id' => 'testclient',
]);
/******************************************************************************/
@@ -144,19 +144,19 @@ Capsule::schema()->create('oauth_access_tokens', function ($table) {
Capsule::table('oauth_access_tokens')->insert([
'access_token' => 'iamgod',
'session_id' => '1',
'expire_time' => time() + 86400
'expire_time' => time() + 86400,
]);
Capsule::table('oauth_access_tokens')->insert([
'access_token' => 'iamalex',
'session_id' => '2',
'expire_time' => time() + 86400
'expire_time' => time() + 86400,
]);
Capsule::table('oauth_access_tokens')->insert([
'access_token' => 'iamphil',
'session_id' => '3',
'expire_time' => time() + 86400
'expire_time' => time() + 86400,
]);
/******************************************************************************/
@@ -199,27 +199,27 @@ Capsule::schema()->create('oauth_access_token_scopes', function ($table) {
Capsule::table('oauth_access_token_scopes')->insert([
'access_token' => 'iamgod',
'scope' => 'basic'
'scope' => 'basic',
]);
Capsule::table('oauth_access_token_scopes')->insert([
'access_token' => 'iamgod',
'scope' => 'email'
'scope' => 'email',
]);
Capsule::table('oauth_access_token_scopes')->insert([
'access_token' => 'iamgod',
'scope' => 'photo'
'scope' => 'photo',
]);
Capsule::table('oauth_access_token_scopes')->insert([
'access_token' => 'iamphil',
'scope' => 'email'
'scope' => 'email',
]);
Capsule::table('oauth_access_token_scopes')->insert([
'access_token' => 'iamalex',
'scope' => 'photo'
'scope' => 'photo',
]);
/******************************************************************************/

View File

@@ -1,29 +1,25 @@
<?php
use \Orno\Http\Request;
use \Orno\Http\Response;
use \Orno\Http\JsonResponse;
use \Orno\Http\Exception\NotFoundException;
use \League\OAuth2\Server\ResourceServer;
use \RelationalExample\Storage;
use \RelationalExample\Model;
use Illuminate\Database\Capsule\Manager as Capsule;
use \League\Event\Emitter;
use Orno\Http\Request;
use Orno\Http\Response;
use RelationalExample\Model;
use RelationalExample\Storage;
include __DIR__.'/vendor/autoload.php';
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
// Set up the OAuth 2.0 authorization server
$server = new \League\OAuth2\Server\AuthorizationServer;
$server->setSessionStorage(new Storage\SessionStorage);
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage);
$server->setClientStorage(new Storage\ClientStorage);
$server->setScopeStorage(new Storage\ScopeStorage);
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
$server = new \League\OAuth2\Server\AuthorizationServer();
$server->setSessionStorage(new Storage\SessionStorage());
$server->setAccessTokenStorage(new Storage\AccessTokenStorage());
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage());
$server->setClientStorage(new Storage\ClientStorage());
$server->setScopeStorage(new Storage\ScopeStorage());
$server->setAuthCodeStorage(new Storage\AuthCodeStorage());
$clientCredentials = new \League\OAuth2\Server\Grant\ClientCredentialsGrant();
$server->addGrantType($clientCredentials);
@@ -47,27 +43,24 @@ $refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
$server->addGrantType($refrehTokenGrant);
// Routing setup
$request = (new Request)->createFromGlobals();
$router = new \Orno\Route\RouteCollection;
$request = (new Request())->createFromGlobals();
$router = new \Orno\Route\RouteCollection();
$router->post('/access_token', function (Request $request) use ($server) {
try {
$response = $server->issueAccessToken();
return new Response(json_encode($response), 200);
} catch (\Exception $e) {
return new Response(
json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]),
$e->httpStatusCode,
$e->getHttpHeaders()
);
}
});
@@ -75,40 +68,30 @@ $router->post('/access_token', function (Request $request) use ($server) {
$dispatcher = $router->getDispatcher();
try {
// A successful response
$response = $dispatcher->dispatch(
$request->getMethod(),
$request->getPathInfo()
);
} catch (\Orno\Http\Exception $e) {
// A failed response
$response = $e->getJsonResponse();
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
$response = new Response(json_encode([
'error' => $e->errorType,
'message' => $e->getMessage()
'message' => $e->getMessage(),
]), $e->httpStatusCode);
foreach ($e->getHttpHeaders() as $header) {
$response->headers($header);
}
} catch (\Exception $e) {
$response = new Orno\Http\Response;
$response = new Orno\Http\Response();
$response->setStatusCode(500);
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
} finally {
// Return the response
$response->headers->set('Content-type', 'application/json');
$response->send();
}