JwtAccessToken.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. namespace OAuth2\ResponseType;
  3. use OAuth2\Encryption\EncryptionInterface;
  4. use OAuth2\Encryption\Jwt;
  5. use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
  6. use OAuth2\Storage\RefreshTokenInterface;
  7. use OAuth2\Storage\PublicKeyInterface;
  8. use OAuth2\Storage\Memory;
  9. /**
  10. * @author Brent Shaffer <bshafs at gmail dot com>
  11. */
  12. class JwtAccessToken extends AccessToken
  13. {
  14. protected $publicKeyStorage;
  15. protected $encryptionUtil;
  16. /**
  17. * @param PublicKeyInterface $publicKeyStorage -
  18. * @param AccessTokenStorageInterface $tokenStorage -
  19. * @param RefreshTokenInterface $refreshStorage -
  20. * @param array $config - array with key store_encrypted_token_string (bool true)
  21. * whether the entire encrypted string is stored,
  22. * or just the token ID is stored
  23. * @param EncryptionInterface $encryptionUtil -
  24. */
  25. public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
  26. {
  27. $this->publicKeyStorage = $publicKeyStorage;
  28. $config = array_merge(array(
  29. 'store_encrypted_token_string' => true,
  30. 'issuer' => ''
  31. ), $config);
  32. if (is_null($tokenStorage)) {
  33. // a pass-thru, so we can call the parent constructor
  34. $tokenStorage = new Memory();
  35. }
  36. if (is_null($encryptionUtil)) {
  37. $encryptionUtil = new Jwt();
  38. }
  39. $this->encryptionUtil = $encryptionUtil;
  40. parent::__construct($tokenStorage, $refreshStorage, $config);
  41. }
  42. /**
  43. * Handle the creation of access token, also issue refresh token if supported / desirable.
  44. *
  45. * @param mixed $client_id - Client identifier related to the access token.
  46. * @param mixed $user_id - User ID associated with the access token
  47. * @param string $scope - (optional) Scopes to be stored in space-separated string.
  48. * @param bool $includeRefreshToken - If true, a new refresh_token will be added to the response
  49. * @return array - The access token
  50. *
  51. * @see http://tools.ietf.org/html/rfc6749#section-5
  52. * @ingroup oauth2_section_5
  53. */
  54. public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
  55. {
  56. // payload to encrypt
  57. $payload = $this->createPayload($client_id, $user_id, $scope);
  58. /*
  59. * Encode the payload data into a single JWT access_token string
  60. */
  61. $access_token = $this->encodeToken($payload, $client_id);
  62. /*
  63. * Save the token to a secondary storage. This is implemented on the
  64. * OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
  65. * if no secondary storage has been supplied
  66. */
  67. $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $payload['id'];
  68. $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
  69. // token to return to the client
  70. $token = array(
  71. 'access_token' => $access_token,
  72. 'expires_in' => $this->config['access_lifetime'],
  73. 'token_type' => $this->config['token_type'],
  74. 'scope' => $scope
  75. );
  76. /*
  77. * Issue a refresh token also, if we support them
  78. *
  79. * Refresh Tokens are considered supported if an instance of OAuth2\Storage\RefreshTokenInterface
  80. * is supplied in the constructor
  81. */
  82. if ($includeRefreshToken && $this->refreshStorage) {
  83. $refresh_token = $this->generateRefreshToken();
  84. $expires = 0;
  85. if ($this->config['refresh_token_lifetime'] > 0) {
  86. $expires = time() + $this->config['refresh_token_lifetime'];
  87. }
  88. $this->refreshStorage->setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
  89. $token['refresh_token'] = $refresh_token;
  90. }
  91. return $token;
  92. }
  93. /**
  94. * @param array $token
  95. * @param mixed $client_id
  96. * @return mixed
  97. */
  98. protected function encodeToken(array $token, $client_id = null)
  99. {
  100. $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
  101. $algorithm = $this->publicKeyStorage->getEncryptionAlgorithm($client_id);
  102. return $this->encryptionUtil->encode($token, $private_key, $algorithm);
  103. }
  104. /**
  105. * This function can be used to create custom JWT payloads
  106. *
  107. * @param mixed $client_id - Client identifier related to the access token.
  108. * @param mixed $user_id - User ID associated with the access token
  109. * @param string $scope - (optional) Scopes to be stored in space-separated string.
  110. * @return array - The access token
  111. */
  112. protected function createPayload($client_id, $user_id, $scope = null)
  113. {
  114. // token to encrypt
  115. $expires = time() + $this->config['access_lifetime'];
  116. $id = $this->generateAccessToken();
  117. return array(
  118. 'id' => $id, // for BC (see #591)
  119. 'jti' => $id,
  120. 'iss' => $this->config['issuer'],
  121. 'aud' => $client_id,
  122. 'sub' => $user_id,
  123. 'exp' => $expires,
  124. 'iat' => time(),
  125. 'token_type' => $this->config['token_type'],
  126. 'scope' => $scope
  127. );
  128. }
  129. }