-
Notifications
You must be signed in to change notification settings - Fork 144
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
Reuse access_token from OAuth login #1407
Reuse access_token from OAuth login #1407
Comments
Hi @ian-paqt. For v2.0 the SDK handles the OAuth request, stores the access token and refreshes the token for you. Here's how to pass your OAuth credentials Here's how to pass them to the GraphServiceClient Thanks for the feedback. Updating the upgrade guide. |
Alright, that sounds neat! And could you specify what |
@ian-paqt should be the tenant that you want to request data from. However, if your application is multi-tenant you can pass Checking the Endpoints on your App Registrations page in Azure would also be useful. |
@Ndiritu I am also having this issue, and I am unsure of how the changes to have the SDK "stores the access token and refreshes the token for you" work in this scenario. I have already had my users go through the OAuth flow and redeem the authorization code for an access_token and refresh_token. Surely, there must be some way to provide an already generated access_token/refresh_token to the client, right? Are authorization codes not short-lived? So with the 2.0 SDK, the User would have to go through the OAuth flow for every request that the Client needs to be instantiated? |
Thanks for the feedback. We need to document this better. Using the info in the $tokenRequestContext = new AuthorizationCodeContext(
'tenantId',
'clientId',
'clientSecret',
'authCode',
'redirectUri'
);
// Adds offline_access scope so that a refresh token is returned during the token request
$scopes = ['User.Read', 'Mail.ReadWrite', 'offline_access'];
$graphServiceClient = new GraphServiceClient($tokenRequestContext, $scopes); The same This way the SDK re-uses the cached access token and refreshes it if it's expired and your user doesn't have to authenticate for every request. Does this help @Orrison @quentinxp? |
I would recommend the approach above however, should you want to handle the tokens yourself:
$authenticationProvider = new CustomAuthenticationProvider($tokenRequestContext, $scopes);
$requestAdapter = new GraphRequestAdapter($authenticationProvider);
$graphServiceClient = GraphServiceClient::createWithRequestAdapter($requestAdapter); |
It is unclear to me how this object could be re-used between requests, let alone sessions. Is it expected that this entire object be persisted in a database or cache? It just seems to me that, though this new functionality of handling the tokens for you is great, it lacks the ability to re-use tokens already obtained out of the box. Which is a very common, if not one of the most used, scenario of interaction with Graph is it not? |
Interesting, this does get us closer to what would be expected to be possible. How would I provide it the refresh_token as well? |
Yes, this is my exact question!
In our application the user authenticates one time. I could use that to instantiate a |
With this approach, all your token requests using the This custom You can then choose to cache these tokens and re-use them within your custom class. You can check our current implementation for reference |
Not really. It would be preferable not to have to cache an entire object and persist these between sessions/requests. Especially since this would also mean I would need to cache this object, per User and create a paradigm for making sure I am using the correct cached object per User... It would be best to simply be able to generate a client easily using an existing and valid
Hmm, I will have to explore this further soon. Still unsure the best way to provide the existing It would be great if this functionality was provided. I think this scenario is just too common, if not the single most common scenario, for the package not to support it natively, IMO. |
For caching, the I agree, it's worth a discussion. I'll get back with feedback from the team. |
Just adding this for info only. I currently download files from user shared folders, and my approach is to get the user to approve the azure application first, and once that is done I request an an offline access token during sign-in a
and then grab the refresh token on redirect, i.e.
You now just only need to save the $refresh_token to a database and use it each time you need to download a file for a particular user. |
So are you using the new Client? And if so, how are you instantiating it with the stored refresh_token? |
any update about this one? I'm also having many access tokens for my users already existed, and I'm not able to reuse them in v2 like I did before in v1. |
I never comment but, this is a very poor implementation. How do we reuse the object ? How do we get the token ? I can get the key OK but how do I set the key? It requires AccessToken object which is not given. The documentation is very bad. It's a terrible package. |
I'm having the same situation, the v2.0 version of this SDK looks promising. However since we're re-using the accessTokens and can't use it (or retrieve it) we can't upgrade to this new version. It would be great if you could add a method to retrieve/refresh the AccessToken and also pass it when creating the GraphServiceClient |
@Ndiritu, is there any update from the team? |
@Ndiritu Do the team have any comments to make? We are trying to make use of SDK 2 but without a method of re-using the tokens we cannot understand how we can keep users logged in across sessions when they use different parts of our web application. We successfully authenticate and retrieve an authCode but we do not store the authCode in our dB as it has a very short expiry, with version 1 of the SDK we stored the access token and the refresh tokens, when the user accessed the web application again in a different session if the token had expired we passed the refresh token to get a new one. We are not sure if we are approaching the flow in the correct way for SDK 2 to keep users logged in across sessions it appears the same issue the above users are experiencing? |
@jamesBotwright thanks for reaching out and apologies for the delay on this. Hoping to have a solution reviewed and released by early next week. |
This is a blocker for us, too. We already store and renew our user's access tokens, and that's a system build for multiple OAuth services, not just the msgraph. This already uses League\OAuth2. And we make sure to renew the token before calling any SDK. And even after reading through here, I still don't know where this SDK is storing or caching anything. There is no storage interface I have to configure. Do you store this on the hard drive or what? That won't work for spawned container instances. Please don't be opinionated on how the access token is obtained or stored. If you want to offer a feature for this, fine, but please make it optional (preferably even in a separate package). |
Please upgrade to version Your feedback is welcome and appreciated. |
--working...
But the access_token I have stored after oauth2.0 flow doesn't contain any "." which results in null |
Our implementation: msgraph v1use Microsoft\Graph\Graph;
class GraphFactory {
public function create(string $accessToken): Graph {
$graph = new Graph();
$graph->setAccessToken($accessToken);
return $graph;
}
} msgraph v2use App\Kernel;
use League\OAuth2\Client\Token\AccessToken;
use Microsoft\Graph\Core\Authentication\GraphPhpLeagueAccessTokenProvider;
use Microsoft\Graph\Core\Authentication\GraphPhpLeagueAuthenticationProvider;
use Microsoft\Graph\GraphServiceClient;
use Microsoft\Kiota\Authentication\Cache\AccessTokenCache;
use Microsoft\Kiota\Authentication\Oauth\AuthorizationCodeContext;
class GraphFactory {
public function create(string $accessToken): GraphServiceClient {
$token = new AccessToken([
'access_token' => $accessToken,
'expires' => time() + 10, //Our AccessTokenProvider makes sure the token is valid for at least 60 seconds
]);
$tokenRequestContext = new class extends AuthorizationCodeContext {
public function __construct() {
//We don't want Microsoft\Graph to request access tokens itself, but all these values may not be empty:
parent::__construct('x', 'x', 'x', 'x', 'x');
}
public function getCacheKey(): ?string {
return 'ignored'; //this ends up as $identity in AccessTokenCache::getAccessToken(), which we don't use
}
};
$cache = new class($token) implements AccessTokenCache {
public function __construct(private readonly AccessToken $token) {
}
public function getAccessToken(string $identity): ?AccessToken {
return $this->token;
}
public function persistAccessToken(string $identity, AccessToken $accessToken): void {
Kernel::$defaultLogger->warning('Microsoft\Graph trying to persist access token!');
}
};
return GraphServiceClient::createWithAuthenticationProvider(
GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider(
GraphPhpLeagueAccessTokenProvider::createWithCache($cache, $tokenRequestContext)
)
);
}
} It's not ideal, but it seems to work. It would be nice if this work flow could be made a bit easier in the future. This all feels like a hack:
|
Thank you for your feedback and the workaround @bilalthepunjabi. Expecting the access token to always be a JWT was a mistake and parsing it isn't recommended. I think generating a UUID to distinguish each user's cached token would be ideal. Would you @uncaught or @bilalthepunjabi be willing to submit a PR for this? It would involve changing the logic here to set the |
@Ndiritu Any update on this for accessing GRAPH SDK using only accessToken? |
Perhaps this solution will prove useful to those who come here: #1472 (comment) |
Hi, thanks for getting the v2.0 update out. It looks promising.
We are currently using v1.x in a project. After an OAuth request we store the access_token. That access_token is than later used to fetch data from the api with this library. In v1.x this used to work like:
From the documentation and upgrade guide I cannot see how we should handle this in v2.0.
Am I missing something? Should we still be able to grab the access_token from somewhere to store for later use?
The text was updated successfully, but these errors were encountered: