Skip to content
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

Upgrade from V1 to V2 - New Authentication-Flow #1490

Open
michaelLoeffelmann opened this issue Mar 25, 2024 · 6 comments
Open

Upgrade from V1 to V2 - New Authentication-Flow #1490

michaelLoeffelmann opened this issue Mar 25, 2024 · 6 comments
Assignees
Labels
area: authentication type:question An issue that's a question

Comments

@michaelLoeffelmann
Copy link

I have an SPA (SinlgePageApplication), which can get an ID and an access token via the msal library. These tokens are included in the header with every request to my API. The API-Gateway routes the request to an microservice that uses the msgraph-sdk-php to communicate with Microsoft.

...
$graph = new Graph();
$graph->setAccessToken(ACCESS_TOKEN_FROM_HEADER);
...

How can I use my given access token together with version 2.x? Because the microservice is not accessible from outside the kubernetes cluster, i can't redirect the user through the OAuth process.

@uncaught
Copy link

You need 2.3 at least and then create an implementation like this: #1407 (comment)

It's a bit cumbersome at the moment. There is more discussion going on in #1469, too.

@dominicgroza72
Copy link

dominicgroza72 commented May 8, 2024

You need 2.3 at least and then create an implementation like this: #1407 (comment)

It's a bit cumbersome at the moment. There is more discussion going on in #1469, too.

I'm trying to do this via your implementation and i get the following error

the server returned an unexpected status code and no error class is registered for this code 401 {"error":{"code":"InvalidAuthenticationToken","message":"IDX14100: JWT is not well formed, there are no dots (.).\nThe token needs to be in JWS or JWE Compact Serialization Format.

class GraphFactory {
    public static 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 {
             Log::warning('Microsoft\Graph trying to persist access token!');
            }
        };

        return GraphServiceClient::createWithAuthenticationProvider(
            GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider(
                GraphPhpLeagueAccessTokenProvider::createWithCache($cache, $tokenRequestContext)
            )
        );
    }
}

$graphClient =
            GraphFactory::create(MicrosoftToken::first()->access_token);
        $user = $graphClient->me()->get()->wait();

@uncaught
Copy link

uncaught commented May 8, 2024

is that coming from your server? then please post a callstack.

if that error comes from Microsoft, then I doubt the implementation here is at fault bc it doesn't modify the token 🤔 does the same token work with v1?

@dominicgroza72
Copy link

dominicgroza72 commented May 9, 2024

@uncaught i wanted to implement v2 directly
I have another problem now,
in my callback function i generate the access token using league/genericProvider

$oauthClient = new GenericProvider([
              'clientId' => env('OAUTH_APP_ID'),
              'clientSecret' => env('OAUTH_APP_PASSWORD'),
              'redirectUri' => env('OAUTH_REDIRECT_URI'),
              'urlAuthorize' => env('OAUTH_AUTHORITY') . 'common' . env('OAUTH_AUTHORIZE_ENDPOINT'),
              'urlAccessToken' => env('OAUTH_AUTHORITY') . 'common' . env('OAUTH_TOKEN_ENDPOINT'),
              'urlResourceOwnerDetails' => '',
              'scopes' => env('OAUTH_SCOPES')
          ]);

          $accessToken = $oauthClient->getAccessToken('authorization_code', [
              'code' => $authCode
              ...
              
                $token->access_token = $accessToken->getToken();
          $token->refresh_token = $accessToken->getRefreshToken();
          $token->expires_at = **now()->addSeconds($accessToken->getExpires());**

this works for a while, but on the next day when i try to use the same tokens to call graph api like such

 $tokenRequestContext = $this->getTokenRequestContext();
   $cache=  new InMemoryAccessTokenCache(
                  $tokenRequestContext,
                  new AccessToken(
                      [
                          'access_token' => $preivouslyStoredAccessToken,
                          'refresh_token' => $previouslyStoredRefreshToken,
                          'expires' => 1
                      ]
                  )
              );
              
              
                $graphServiceClient = GraphServiceClient::createWithAuthenticationProvider(
          GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider(
              GraphPhpLeagueAccessTokenProvider::createWithCache(
                  $cache,
                  $tokenRequestContext,
                  $scopes
              )
          )
      );

      $user = $graphServiceClient->me()->messages()->get()->wait();
              
              
              
              
    private function getTokenRequestContext()
  {
      return 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
          }
      };
  }

i get the following error when calling graphServiceClient https://flareapp.io/share/Lm8KN3A5

@uncaught
Copy link

uncaught commented May 9, 2024

I am not sure, what you are trying to do there. Access tokens usually don't last very long. Like 30min is common. After that you have to use the refresh token to get a new access token.

If you have not already implemented a refresh system, may I suggest you take a step back and let this repo handle it for you, as it was designed to? All you need is to implement the persistence layer then. But that's not what this issue here is about.

@kintumiku
Copy link

You need 2.3 at least and then create an implementation like this: #1407 (comment)
It's a bit cumbersome at the moment. There is more discussion going on in #1469, too.

I'm trying to do this via your implementation and i get the following error

the server returned an unexpected status code and no error class is registered for this code 401 {"error":{"code":"InvalidAuthenticationToken","message":"IDX14100: JWT is not well formed, there are no dots (.).\nThe token needs to be in JWS or JWE Compact Serialization Format.

class GraphFactory {
    public static 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 {
             Log::warning('Microsoft\Graph trying to persist access token!');
            }
        };

        return GraphServiceClient::createWithAuthenticationProvider(
            GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider(
                GraphPhpLeagueAccessTokenProvider::createWithCache($cache, $tokenRequestContext)
            )
        );
    }
}

$graphClient =
            GraphFactory::create(MicrosoftToken::first()->access_token);
        $user = $graphClient->me()->get()->wait();

Hi, how was this issue resolved?

@Ndiritu Ndiritu added area: authentication type:question An issue that's a question labels Aug 8, 2024
@Ndiritu Ndiritu self-assigned this Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: authentication type:question An issue that's a question
Projects
None yet
Development

No branches or pull requests

5 participants