oauth2-server-php
oauth2-server-php copied to clipboard
OpenId Connect - TokenController does Not send id_token
This got discussed in #443, but I think I am missing something, or there is some kind of problem here:
- according to Google's implementation (https://developers.google.com/accounts/docs/OpenIDConnect) an
id_token
should always be returned when accessing the token endpoint. I cannot get this to happen.
After making an authorize
request like this:
https://localhost:8443/core_auth/web/oauth/v1/authorize?client_id=app_id&response_type=code&redirect_uri=https%3A%2F%2Flocalhst%...&scope=openid profile email
I only get responses like this:
{
"access_token": "3a7447b3...",
"expires_in": 86400,
"token_type": "Bearer",
"scope": "openid profile email",
"refresh_token": "4116587..."
}
There is no id_token
.
I am using the following config:
'options' => [
'token_param_name' => 'access_token',
'access_lifetime' => 3600 * 24,
'enforce_state' => true,
'allow_implicit' => true,
'use_openid_connect' => true,
'require_exact_redirect_uri' => false, // TODO: should be exact ?!
'enforce_state' => false // TODO: remove! should be true
],
Is this an expected behavior?
Thanks in advance!!
This is not entirely the expected behavior. When openid
is presented in scope
to should return a id_token
as well but it has nothing to do with your code. I am in the same boat where the sever is not returning the id_token
when the using response_type=code
.
However the functionality does work with the implicit method. I am doing some poking around as well but with no luck yet.
@justingreerbbi have you tried supplying response_type=code id_token
?
@belerophon @justingreerbbi Hi, did you forgot to implement AuthorizationCodeInterface
for OpenId and save to storage the id_token
value, which is set to null
by default?
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, ***$id_token = null***);
I have configuration:
'options' => [
...
'allow_implicit' => false,
'use_openid_connect' => true,
'issuer' => 'Me'
]
And I request for response type of code
and scope openid
.
This works for me. It was't until I have save token to storage.
As a side, @bshaffer if I specify in scope other things, like email it is not included in idToken.
Gettting user claims works only in case of implicit grant
The reason for that is the AuthorizationController
is not passing scopes - claims when calling createIdToken
https://github.com/bshaffer/oauth2-server-php/blob/develop/src/OAuth2/OpenID/Controller/AuthorizeController.php#L43
Is this done with purpose?
I came up with a solution by passing the the id token to setAuthorizationCode and then modifying the codes table in the DB to handle an ID to pass back.
I was not able to get it to work just by modifying the settings. All responses came back in the URL or implicit and not in the JSON response as specified in spec.
I had the same issue, but it was my fault. I forget to add the openId grant type to the server
$server->addGrantType(new OAuth2\OpenID\GrantType\AuthorizationCode($storage));
Hi @bshaffer,
As already reported by @belerophon on 12 Mar 15, the Token Endpoint of a compliant OpenID Provider MUST always include an ID Token in the response.
See OpenID Connect Core 1.0 specification, point 3.1.3.3 "Successful Token Response":
In addition to the response parameters specified by OAuth 2.0, the following parameters MUST be included in the response:
- id_token : ID Token value associated with the authenticated session...
For this reason, a custom TokenController must be implemented for OpenId. Please note that this applies for the Token Endpoint, and not the Authorization Endpoint for which an ID Token is returned depending on the value of the response_type parameter.
Kind regards, Rodolphe Cardon
This problem can be solved by using
$server->addGrantType(new OAuth2\OpenID\GrantType\AuthorizationCode($storage));
instead of
$server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));
The GrantType class AuthorizationCode
in the OpenID package implements the createAccessToken
function that add the id_token
parameter when the Token Endpoint is called.
This should be documented on the OpenId Connect page. http://bshaffer.github.io/oauth2-server-php-docs/overview/openid-connect/
Following @cardonr's advice, I implemented an OIDC-specific token controller. This was also able to fix another issue I was having with custom claims not being included in the id_token (#763).
+++ b/lib/OAuth2/OpenID/Controller/TokenController.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace OAuth2\OpenID\Controller;
+
+use OAuth2\ResponseType\AccessTokenInterface;
+use OAuth2\ClientAssertionType\ClientAssertionTypeInterface;
+use OAuth2\Controller\TokenControllerInterface;
+use OAuth2\ScopeInterface;
+use OAuth2\Storage\ClientInterface;
+use OAuth2\RequestInterface;
+use OAuth2\ResponseInterface;
+use OAuth2\Controller\TokenController as BaseController;
+
+class TokenController extends BaseController implements TokenControllerInterface
+{
+ protected $idToken;
+ protected $userClaimsStorage;
+
+ public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, IdTokenInterface $idToken, UserClaimsInterface $userClaimsStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
+ {
+ parent::__construct($accessToken, $clientStorage, $grantTypes, $clientAssertionType, $scopeUtil);
+
+ $this->idToken = $idToken;
+ $this->userClaimsStorage = $userClaimsStorage;
+ }
+
+ public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
+ {
+ $accessToken = parent::grantAccessToken($request, $response);
+
+ if ($accessToken != null && array_key_exists('scope', $accessToken) && in_array('openid', explode(' ', $accessToken['scope']))) {
+ $grantTypeIdentifier = $request->request('grant_type');
+ $grantType = $this->grantTypes[$grantTypeIdentifier];
+
+ $userId = $grantType->getUserId();
+ $scope = $grantType->getScope();
+
+ $claims = $this->userClaimsStorage->getUserClaims($userId, $scope);
+ $accessToken['id_token'] = $this->idToken->createIdToken($grantType->getClientId(), $userId, null, $claims);
+ }
+
+ return $accessToken;
+ }
+}
diff --git a/lib/OAuth2/Server.php b/lib/OAuth2/Server.php
index 171a4f0..d38f9f1 100644
--- a/lib/OAuth2/Server.php
+++ b/lib/OAuth2/Server.php
@@ -4,6 +4,7 @@ namespace OAuth2;
use OAuth2\Controller\ResourceControllerInterface;
use OAuth2\Controller\ResourceController;
+use OAuth2\OpenID\Controller\TokenController as OpenIDTokenController;
use OAuth2\OpenID\Controller\UserInfoControllerInterface;
use OAuth2\OpenID\Controller\UserInfoController;
use OAuth2\OpenID\Controller\AuthorizeController as OpenIDAuthorizeController;
@@ -520,6 +521,10 @@ class Server implements ResourceControllerInterface,
$accessTokenResponseType = $this->getAccessTokenResponseType();
+ if ($this->config['use_openid_connect']) {
+ return new OpenIDTokenController($accessTokenResponseType, $this->storages['client'], $this->getIdTokenResponseType(), $this->storages['user_claims'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
+ }
+
return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
}
Following @biwerr , adding the OpenID grant type worked for me. In hindsight it makes sense, but I didn't come across it in the documentation.
So, if you're like me and you've set use_openid_connect and the id_tokens are being generated properly (but never sent), I recommend adding the OpenID AuthorizationCode grant:
$server->addGrantType(new OAuth2\OpenID\GrantType\AuthorizationCode($storage));
see https://github.com/bshaffer/oauth2-server-php/issues/544#issuecomment-164734763
@cardonr @bshaffer What should I do when implementing Password Credential Grant
for OIDC logins?
Because in this case we're completely skipping authorization step and if token endpoint doesnt return id_token
.... then what?
How can I make token endpoint return id_token
with this library?