mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3bec591393 | ||
|
084b779cc6 | ||
|
491f3f0e95 | ||
|
c5db707e69 | ||
|
ed7f78179a | ||
|
6e92239dd7 | ||
|
f5d731def9 | ||
|
03815cec6d | ||
|
c71dc47459 | ||
|
3bcd8fc3f8 | ||
|
db6d4e0dc6 | ||
|
f19189a999 | ||
|
ec9c91cc11 | ||
|
c3457107ee | ||
|
a9f61fd3ed | ||
|
b78d8ca1d8 | ||
|
8f82e8ef86 | ||
|
d88e01c7dd | ||
|
d21374fb0b | ||
|
31e5f4d33c | ||
|
a773405adf | ||
|
ccc845b195 | ||
|
21cd917892 | ||
|
a2c418ee07 | ||
|
b220368583 | ||
|
2d26c38d6c | ||
|
eeaa68400f | ||
|
56c73d2427 | ||
|
f632fcc997 | ||
|
618d84ddcf | ||
|
ace42e89e0 | ||
|
c496df98e4 | ||
|
2496653968 | ||
|
abf66ef9c8 | ||
|
4b9ec488f4 | ||
|
726d879607 | ||
|
b256195421 | ||
|
c84ea1ea62 | ||
|
16685ccde4 | ||
|
7934c7bb53 | ||
|
c174b6fc65 | ||
|
75ced70248 | ||
|
5b7fdaeece | ||
|
430a752315 | ||
|
810544ec0a |
@@ -21,8 +21,7 @@ checks:
|
||||
fix_doc_comments: true
|
||||
tools:
|
||||
external_code_coverage:
|
||||
timeout: 600
|
||||
runs: 3
|
||||
timeout: 1800
|
||||
php_code_coverage: false
|
||||
php_code_sniffer:
|
||||
config:
|
||||
@@ -34,4 +33,4 @@ tools:
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
php_cpd:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
|
@@ -26,8 +26,8 @@ script:
|
||||
- phpunit --coverage-text --verbose --coverage-clover=coverage.clover --coverage-html coverage
|
||||
|
||||
after_script:
|
||||
- wget https://scrutinizer-ci.com/ocular.phar
|
||||
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
|
||||
- bash -c 'if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi;
|
||||
- bash -c 'if [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi;
|
||||
- git config --global user.email "travis@travis-ci.org"
|
||||
- git config --global user.name "TravisCI"
|
||||
- cp -R coverage ${HOME}/coverage
|
||||
|
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,5 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## 4.1.6 (released 2016-09-13)
|
||||
|
||||
* Less restrictive on Authorization header check (Issue #652)
|
||||
|
||||
## 4.1.5 (released 2016-01-04)
|
||||
|
||||
* Enable Symfony 3.0 support (#412)
|
||||
|
||||
## 4.1.4 (released 2015-11-13)
|
||||
|
||||
* Fix for determining access token in header (Issue #328)
|
||||
* Refresh tokens are now returned for MAC responses (Issue #356)
|
||||
* Added integration list to readme (Issue #341)
|
||||
* Expose parameter passed to exceptions (Issue #345)
|
||||
* Removed duplicate routing setup code (Issue #346)
|
||||
* Docs fix (Issues #347, #360, #380)
|
||||
* Examples fix (Issues #348, #358)
|
||||
* Fix typo in docblock (Issue #352)
|
||||
* Improved timeouts for MAC tokens (Issue #364)
|
||||
* `hash_hmac()` should output raw binary data, not hexits (Issue #370)
|
||||
* Improved regex for matching all Base64 characters (Issue #371)
|
||||
* Fix incorrect signature parameter (Issue #372)
|
||||
* AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377)
|
||||
* Added priority argument to event listener (Issue #388)
|
||||
|
||||
## 4.1.3 (released 2015-03-22)
|
||||
|
||||
* Docblock, namespace and inconsistency fixes (Issue #303)
|
||||
* Docblock type fix (Issue #310)
|
||||
* Example bug fix (Issue #300)
|
||||
* Updated league/event to ~2.1 (Issue #311)
|
||||
* Fixed missing session scope (Issue #319)
|
||||
* Updated interface docs (Issue #323)
|
||||
* `.travis.yml` updates
|
||||
|
||||
## 4.1.2 (released 2015-01-01)
|
||||
|
||||
* Remove side-effects in hash_equals() implementation (Issue #290)
|
||||
|
@@ -51,6 +51,11 @@ Contribute to this documentation in the [gh-pages branch](https://github.com/the
|
||||
|
||||
Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) for details.
|
||||
|
||||
## Integration
|
||||
|
||||
- [CakePHP 3](https://github.com/uafrica/oauth-server)
|
||||
- [Laravel](https://github.com/lucadegasperi/oauth2-server-laravel)
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues)
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"symfony/http-foundation": "~2.4",
|
||||
"symfony/http-foundation": "~2.4|~3.0",
|
||||
"league/event": "~2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@@ -9,11 +9,6 @@ use RelationalExample\Storage;
|
||||
|
||||
include __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request())->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection();
|
||||
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
|
||||
|
||||
// Set up the OAuth 2.0 resource server
|
||||
$sessionStorage = new Storage\SessionStorage();
|
||||
$accessTokenStorage = new Storage\AccessTokenStorage();
|
||||
|
@@ -122,10 +122,11 @@ abstract class AbstractServer
|
||||
*
|
||||
* @param string $eventName Event name
|
||||
* @param callable $listener Callable function or method
|
||||
* @param int $priority Priority of event listener
|
||||
*/
|
||||
public function addEventListener($eventName, callable $listener)
|
||||
public function addEventListener($eventName, callable $listener, $priority = Emitter::P_NORMAL)
|
||||
{
|
||||
$this->eventEmitter->addListener($eventName, $listener);
|
||||
$this->eventEmitter->addListener($eventName, $listener, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -20,7 +20,7 @@ use League\OAuth2\Server\TokenType\Bearer;
|
||||
class AuthorizationServer extends AbstractServer
|
||||
{
|
||||
/**
|
||||
* The delimeter between scopes specified in the scope query string parameter
|
||||
* The delimiter between scopes specified in the scope query string parameter
|
||||
* The OAuth 2 specification states it should be a space but most use a comma
|
||||
*
|
||||
* @var string
|
||||
|
@@ -32,6 +32,7 @@ class InvalidGrantException extends OAuthException
|
||||
|
||||
public function __construct($parameter)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. Check the "%s" parameter.',
|
||||
|
@@ -32,6 +32,7 @@ class InvalidRequestException extends OAuthException
|
||||
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
|
@@ -32,6 +32,7 @@ class InvalidScopeException extends OAuthException
|
||||
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.',
|
||||
|
@@ -36,6 +36,11 @@ class OAuthException extends \Exception
|
||||
*/
|
||||
public $errorType = '';
|
||||
|
||||
/**
|
||||
* Parameter eventually passed to Exception
|
||||
*/
|
||||
public $parameter = '';
|
||||
|
||||
/**
|
||||
* Throw a new exception
|
||||
*
|
||||
@@ -72,6 +77,16 @@ class OAuthException extends \Exception
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return parameter if set
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getParameter()
|
||||
{
|
||||
return $this->parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
*
|
||||
|
@@ -31,7 +31,9 @@ class ServerErrorException extends OAuthException
|
||||
*/
|
||||
public function __construct($parameter = null)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
$parameter = is_null($parameter) ? 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' : $parameter;
|
||||
parent::__construct($parameter);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ class UnsupportedGrantTypeException extends OAuthException
|
||||
|
||||
public function __construct($parameter)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The authorization grant type "%s" is not supported by the authorization server.',
|
||||
|
@@ -31,6 +31,7 @@ class UnsupportedResponseTypeException extends OAuthException
|
||||
*/
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
$this->parameter = $parameter;
|
||||
parent::__construct('The authorization server does not support obtaining an access token using this method.');
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
@@ -60,6 +60,14 @@ class AuthCodeGrant extends AbstractGrant
|
||||
*/
|
||||
protected $authTokenTTL = 600;
|
||||
|
||||
/**
|
||||
* Whether to require the client secret when
|
||||
* completing the flow.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireClientSecret = true;
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
*
|
||||
@@ -72,6 +80,27 @@ class AuthCodeGrant extends AbstractGrant
|
||||
$this->authTokenTTL = $authTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bool $required True to require client secret during access
|
||||
* token request. False if not. Default = true
|
||||
*/
|
||||
public function setRequireClientSecret($required)
|
||||
{
|
||||
$this->requireClientSecret = $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if client secret is required during
|
||||
* access token request. False if it isn't.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRequireClientSecret()
|
||||
{
|
||||
return $this->requireClientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check authorize parameters
|
||||
*
|
||||
@@ -184,7 +213,7 @@ class AuthCodeGrant extends AbstractGrant
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret',
|
||||
$this->server->getRequest()->getPassword());
|
||||
if (is_null($clientSecret)) {
|
||||
if ($this->shouldRequireClientSecret() && is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
|
||||
@@ -271,4 +300,4 @@ class AuthCodeGrant extends AbstractGrant
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,7 +19,7 @@ use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
|
||||
/**
|
||||
* Referesh token grant
|
||||
* Refresh token grant
|
||||
*/
|
||||
class RefreshTokenGrant extends AbstractGrant
|
||||
{
|
||||
@@ -42,6 +42,14 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
*/
|
||||
protected $refreshTokenRotate = true;
|
||||
|
||||
/**
|
||||
* Whether to require the client secret when
|
||||
* completing the flow.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireClientSecret = true;
|
||||
|
||||
/**
|
||||
* Set the TTL of the refresh token
|
||||
*
|
||||
@@ -83,6 +91,28 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
return $this->refreshTokenRotate;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bool $required True to require client secret during access
|
||||
* token request. False if not. Default = true
|
||||
*/
|
||||
public function setRequireClientSecret($required)
|
||||
{
|
||||
$this->requireClientSecret = $required;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if client secret is required during
|
||||
* access token request. False if it isn't.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRequireClientSecret()
|
||||
{
|
||||
return $this->requireClientSecret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -95,7 +125,7 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret',
|
||||
$this->server->getRequest()->getPassword());
|
||||
if (is_null($clientSecret)) {
|
||||
if ($this->shouldRequireClientSecret() && is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
|
||||
@@ -190,4 +220,4 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\TokenType\Bearer;
|
||||
use League\OAuth2\Server\TokenType\MAC;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
@@ -137,9 +138,9 @@ class ResourceServer extends AbstractServer
|
||||
*/
|
||||
public function determineAccessToken($headerOnly = false)
|
||||
{
|
||||
if ($this->getRequest()->headers->get('Authorization') !== null) {
|
||||
if (!empty($this->getRequest()->headers->get('Authorization'))) {
|
||||
$accessToken = $this->getTokenType()->determineAccessTokenInHeader($this->getRequest());
|
||||
} elseif ($headerOnly === false) {
|
||||
} elseif ($headerOnly === false && (! $this->getTokenType() instanceof MAC)) {
|
||||
$accessToken = ($this->getRequest()->server->get('REQUEST_METHOD') === 'GET')
|
||||
? $this->getRequest()->query->get($this->tokenKey)
|
||||
: $this->getRequest()->request->get($this->tokenKey);
|
||||
|
@@ -38,9 +38,16 @@ class Bearer extends AbstractTokenType implements TokenTypeInterface
|
||||
*/
|
||||
public function determineAccessTokenInHeader(Request $request)
|
||||
{
|
||||
$header = $request->headers->get('Authorization');
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header));
|
||||
if ($request->headers->has('Authorization') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
return ($accessToken === 'Bearer') ? '' : $accessToken;
|
||||
$header = $request->headers->get('Authorization');
|
||||
|
||||
if (substr($header, 0, 7) !== 'Bearer ') {
|
||||
return;
|
||||
}
|
||||
|
||||
return trim(substr($header, 7));
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,10 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
'mac_algorithm' => 'hmac-sha-256',
|
||||
];
|
||||
|
||||
if (!is_null($this->getParam('refresh_token'))) {
|
||||
$response['refresh_token'] = $this->getParam('refresh_token');
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -61,7 +65,7 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
array_map(function ($param) use (&$params) {
|
||||
$param = trim($param);
|
||||
|
||||
preg_match_all('/([a-zA-Z]*)="([\w=]*)"/', $param, $matches);
|
||||
preg_match_all('/([a-zA-Z]*)="([\w=\/+]*)"/', $param, $matches);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (count($matches) !== 3) {
|
||||
@@ -84,7 +88,7 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) $params->get('ts') !== time()) {
|
||||
if (abs($params->get('ts') - time()) > 300) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,7 +109,7 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
$timestamp,
|
||||
$nonce,
|
||||
strtoupper($request->getMethod()),
|
||||
$request->getUri(),
|
||||
$request->getRequestUri(),
|
||||
$request->getHost(),
|
||||
$request->getPort(),
|
||||
];
|
||||
@@ -114,7 +118,14 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
$calculatedSignatureParts[] = $params->get('ext');
|
||||
}
|
||||
|
||||
$calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), $macKey));
|
||||
$calculatedSignature = base64_encode(
|
||||
hash_hmac(
|
||||
'sha256',
|
||||
implode("\n", $calculatedSignatureParts),
|
||||
$macKey,
|
||||
true // raw_output: outputs raw binary data
|
||||
)
|
||||
);
|
||||
|
||||
// Return the access token if the signature matches
|
||||
return ($this->hash_equals($calculatedSignature, $signature)) ? $accessToken : null;
|
||||
|
@@ -498,4 +498,73 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue(array_key_exists('expires_in', $response));
|
||||
$this->assertEquals($response['refresh_token'], $_POST['refresh_token']);
|
||||
}
|
||||
|
||||
public function testCompleteFlowShouldRequireClientSecret()
|
||||
{
|
||||
$_POST = [
|
||||
'grant_type' => 'refresh_token',
|
||||
'client_id' => 'testapp',
|
||||
'refresh_token' => 'refresh_token',
|
||||
];
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$grant = new RefreshTokenGrant();
|
||||
$grant->setRequireClientSecret(false);
|
||||
|
||||
$clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface');
|
||||
$clientStorage->shouldReceive('setServer');
|
||||
$clientStorage->shouldReceive('get')->andReturn(
|
||||
(new ClientEntity($server))->hydrate(['id' => 'testapp'])
|
||||
);
|
||||
|
||||
$sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface');
|
||||
$sessionStorage->shouldReceive('setServer');
|
||||
$sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]);
|
||||
$sessionStorage->shouldReceive('associateScope');
|
||||
$sessionStorage->shouldReceive('getByAccessToken')->andReturn(
|
||||
(new SessionEntity($server))
|
||||
);
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('setServer');
|
||||
$accessTokenStorage->shouldReceive('get')->andReturn(
|
||||
(new AccessTokenEntity($server))
|
||||
);
|
||||
$accessTokenStorage->shouldReceive('delete');
|
||||
$accessTokenStorage->shouldReceive('create');
|
||||
$accessTokenStorage->shouldReceive('getScopes')->andReturn([
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'foo']),
|
||||
]);
|
||||
$accessTokenStorage->shouldReceive('associateScope');
|
||||
|
||||
$refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface');
|
||||
$refreshTokenStorage->shouldReceive('setServer');
|
||||
$refreshTokenStorage->shouldReceive('associateScope');
|
||||
$refreshTokenStorage->shouldReceive('delete');
|
||||
$refreshTokenStorage->shouldReceive('create');
|
||||
$refreshTokenStorage->shouldReceive('get')->andReturn(
|
||||
(new RefreshTokenEntity($server))->setId('refresh_token')->setExpireTime(time() + 86400)
|
||||
);
|
||||
|
||||
$scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface');
|
||||
$scopeStorage->shouldReceive('setServer');
|
||||
$scopeStorage->shouldReceive('get')->andReturn(
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'foo'])
|
||||
);
|
||||
|
||||
$server->setClientStorage($clientStorage);
|
||||
$server->setScopeStorage($scopeStorage);
|
||||
$server->setSessionStorage($sessionStorage);
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
$server->setRefreshTokenStorage($refreshTokenStorage);
|
||||
|
||||
$server->addGrantType($grant);
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
$this->assertTrue(array_key_exists('access_token', $response));
|
||||
$this->assertTrue(array_key_exists('refresh_token', $response));
|
||||
$this->assertTrue(array_key_exists('token_type', $response));
|
||||
$this->assertTrue(array_key_exists('expires_in', $response));
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -52,12 +52,12 @@ class MacTest extends \PHPUnit_Framework_TestCase
|
||||
$ts,
|
||||
'foo',
|
||||
strtoupper($request->getMethod()),
|
||||
$request->getUri(),
|
||||
$request->getRequestUri(),
|
||||
$request->getHost(),
|
||||
$request->getPort(),
|
||||
'ext'
|
||||
];
|
||||
$calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), 'abcdef'));
|
||||
$calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), 'abcdef', true));
|
||||
|
||||
$request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, $calculatedSignature));
|
||||
|
||||
|
Reference in New Issue
Block a user