microsoftgraph / microsoftgraph/msgraph-sdk-php
access_token from OAuth login: already redeemed
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 669
- Forks
- 150
- Avg merge
- 15h 21m
- Merged PRs (30d)
- 3
Description
Hello everyone!
I've successfully implemented a proof of concept for an application with Authorization Code Flow.
Calling the code below by browser, shows expected informations, BUT when one reloads the "page" a
"IdentityProviderException" with message "invalid_grant" occures - wich is really missleading IMHO.
Digging deeper one finds this "error_description":
"AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code ..."
The code below (as a proof of concept) is part of a SaaS application and should handle different taks.
In this sceanario above exception is thrown from second try to use the script.
As you can see, the "access_token" is not used directly but it seems the SDK uses it internally.
Is there a clean implementation to avoid such exceptions?
I have already a "brute force solution" by redirecting all new calls to the script
to 'https://login.microsoftonline.com/'.TENANT_ID.'/oauth2/v2.0/authorize'
but this realy, realy ugly and far from a clean solution I think.
What is wrong with this code or is this a "misbehavior" of SDK?
const TENANT_ID = '...';
const CLIENT_ID = '...';
const SECRET = '...';
const REDIRECT_TO_URI = 'https://example.com/GraphApplicationTest.php'; // placeholder!!
const MS_AUTHORIZE_URI = 'https://login.microsoftonline.com/'.TENANT_ID.'/oauth2/v2.0/authorize';
const MS_TOKEN_URI = 'https://login.microsoftonline.com/'.TENANT_ID.'/oauth2/v2.0/token';
const MS_RESSOURCE_URI = 'https://login.microsoftonline.com/'.TENANT_ID;
$basicScopes = [ 'https://graph.microsoft.com/.default' ];
$extendedScopes = [
'openid',
'offline_access',
'User.Read',
'User.Read.All',
'User.ReadBasic.All',
];
$oauthGenProvider = NULL;
$authCode = "";
$accessToken = NULL;
$nextToken = NULL;
$tokenContext = NULL;
$oauthGenProvider = new GenericProvider([
'clientId' => CLIENT_ID,
'clientSecret' => SECRET,
'redirectUri' => REDIRECT_TO_URI,
'urlAuthorize' => MS_AUTHORIZE_URI,
'urlAccessToken' => MS_TOKEN_URI,
'urlResourceOwnerDetails' => MS_RESSOURCE_URI,
'scopes' => $basicScopes,
],
);
// check errors from eventually previous request
if ( isset( $_GET['error'] ) )
{
echo "<pre>";
echo "exiting with error!\n\n";
echo "error: ".$_GET['error']."\n";
echo "description:\n ".$_GET['error_description']."\n";
exit;
}
// if not authenticated goto "login"
if (!isset($_GET['code']))
{
$authorizationUrl = $oauthGenProvider->getAuthorizationUrl();
header('Location: ' . $authorizationUrl);
exit;
}
echo "<pre>";
echo "SDK version is ".GraphConstants::SDK_VERSION."\n";
$authCode = $_GET['code'];
// first step to prepare for "GraphServiceClient": create a context of type "AuthorizationCodeContext"
// Microsoft\Kiota\Authentication\Oauth\AuthorizationCodeContext
// https://github.com/microsoft/kiota-authentication-phpleague-php/blob/main/src/Oauth/AuthorizationCodeContext.php
$tokenContext = new AuthorizationCodeContext(
TENANT_ID,
CLIENT_ID,
SECRET,
$authCode,
REDIRECT_TO_URI,
);
$graphClient = new GraphServiceClient($tokenContext, $extendedScopes);
try
{
$users = $graphClient->users()->get()->wait();
$userList = $users->getValue(); // returns an array!
// $userList[x] <==> Microsoft\Graph\Generated\Models\User
// https://github.com/microsoftgraph/msgraph-sdk-php/blob/main/src/Generated/Models/User.php
echo " user[0] display name: ".$userList[0]->getDisplayName()."\n";
}
catch ( Exception $e )
{
if ( $e instanceof \League\OAuth2\Client\Provider\Exception\IdentityProviderException )
{
echo " IdentityProviderException\n";
echo $e->getResponseBody()["error_description"];
// AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.
}
else
{
echo " Exception";
}
echo $e->getMessage()."\n";
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the OAuth flow around GenericProvider, AuthorizationCodeContext, and GraphServiceClient, then reproduce the failure by reloading the callback URL. Compare the first and second requests and determine whether the SDK should handle the redeemed authorization code differently; done should include a clear expected behavior or documented usage path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- api, authentication
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100