-
Notifications
You must be signed in to change notification settings - Fork 212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ID token validation #285
Conversation
9b4558b
to
ffa8e49
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add the missing tests
src/Auth0.php
Outdated
'client_secret' => $this->clientSecret, | ||
'secret_base64_encoded' => $this->clientSecretEncoded, | ||
'authorized_iss' => [ $issuer ], | ||
'supported_algs' => [ 'HS256', 'RS256' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be a setting / parameter?
src/Auth0.php
Outdated
'secret_base64_encoded' => $this->clientSecretEncoded, | ||
'authorized_iss' => [ $issuer ], | ||
'supported_algs' => [ 'HS256', 'RS256' ], | ||
'valid_audiences' => [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this should be a param too. What if the user requests a token for a custom API ? audience will appear here
src/Auth0.php
Outdated
$issuer = 'https://'.$this->domain.'/'; | ||
$jwtVerifier = new JWTVerifier([ | ||
'guzzle_options' => $this->guzzleOptions, | ||
'client_secret' => $this->clientSecret, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's this and the param below user for if the alg happens to be RS?
src/Auth0.php
Outdated
} catch (\Exception $e) { | ||
$message = 'ID token could not be validated.'; | ||
if ($e->getMessage()) { | ||
$message .= ' '.$e->getMessage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to prepend ' '
? Can't you do that on the "if" with something like isEmpty($e->getMessage())?
src/Auth0.php
Outdated
@@ -556,9 +565,35 @@ public function setAccessToken($accessToken) | |||
* @param string $idToken - ID token returned from the code exchange. | |||
* | |||
* @return \Auth0\SDK\Auth0 | |||
* | |||
* @throws CoreException If ID token did not validate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd add here or in the readme (docs, wherever) all the special cases you mentioned on the PR's description. e.g. the leeway when time verification fails
aec4347
to
281bd0b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💣 💥 🙉
src/API/Helpers/TokenGenerator.php
Outdated
|
||
/** | ||
* @param array $scopes Array of scopes to include. | ||
* @param integer $lifetime Lifetime of the token. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor but "in seconds"
src/API/Helpers/TokenGenerator.php
Outdated
*/ | ||
protected function bstr2bin($input) | ||
public function __construct($client_id, $client_secret) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this class is called "TokenGenerator" what about renaming this props to audience
and secret
, so they refer more to a generic token rather than auth0
* Class TokenGenerator. | ||
* Generates HS256 ID tokens. | ||
* | ||
* @package Auth0\SDK\API\Helpers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imagine this class is only used on tests, right? If so, wouldn't the correct namespace be under a test
folder?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's how it's used in the SDK, yes, but it's already in a public namespace so removing would be breaking. Making a note of this for the major.
src/Auth0.php
Outdated
@@ -71,6 +72,13 @@ class Auth0 | |||
*/ | |||
protected $clientSecret; | |||
|
|||
/** | |||
* Is the Auth0 Client Secret encoded? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd not make this a question and add where I can know this information. e.g. "Check in your Application's settings under the Client Secret field."
/** | ||
* Algorithm to use for ID token validation. | ||
* | ||
* @var string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess there are a set of allowed values?
* | ||
* @codeCoverageIgnore | ||
*/ | ||
private function supportsAlg($alg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you're using this in 2 or 3 places so I get why you moved this to a method. But this sounds more like a "array contains" method. (which you're using in many other places such as when comparing audiences). Consider refactoring this 🆗
src/JWTVerifier.php
Outdated
*/ | ||
private function decodeTokenSegment($segment) | ||
{ | ||
return JWT::jsonDecode(JWT::urlsafeB64Decode($segment)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not make the "base64 decode part" call the method you defined above --> decodeB64 ?
@@ -1,12 +1,14 @@ | |||
<?php | |||
namespace Auth0\Tests\API; | |||
|
|||
use Auth0\Tests\Traits\ErrorHelpers; | |||
use Auth0\SDK\API\Helpers\TokenGenerator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I mentioned this in a comment above, but this token generator seems to be only used on this test. Please move it to the /Test/
folder so users don't use it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above
* | ||
* @return void | ||
*/ | ||
public function testThatMissingSecretThrowsException() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in general, use the method name to describe the test as most as possible. e.g. testThatMissingSecretWhenUsingHS256ThrowsException
'client_secret' => $client_secret, | ||
'secret_base64_encoded' => false | ||
] | ||
// 2. Test that a non-encoded client secret can be used. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to split this test into 2 separate ones. When a test fails is easier to read that by reading the test/method name rather than having to look at the line of code that caused this to fail.
23d010c
to
e155c56
Compare
src/JWTVerifier.php
Outdated
* | ||
* @var JWKFetcher|null | ||
*/ | ||
protected $jwks_fetcher = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is protected. Changing this name will make subclasses break AFAIK.
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This SDK already had a
JWTVerifier
class to verify ID tokens but that class was not being used in the default login route. This PR adds this validation toAuth0\SDK\Auth0::setIdToken()
before the incoming ID token is stored. Underlying validation library is Firebase JWT.What is validated
Potential issues
NBF and IAT validation
Both of these values check a timecode in the token payload against the time set on the server doing the validation. If your server time is different from the issuing server, this could cause the validation to fail. If you're getting an error message stating
Cannot handle token prior to ...
, then you can try setting a leeway in the Firebase JWT library, like this:Client Secret encoding
Most tenants will not have a base64-encoded Client Secret but older tenants might. It will display on your Application settings page whether this is the case or not:
By default, the JWT verifier uses the Client Secret as-is with no decoding. If your Client Secret is encoded, add a new value to your
Auth0
initialization array like this: