cant get token from laravel passport with authorization_code flow - php

im using laravel passport and i want to get a token like this
https://laravel.com/docs/9.x/passport#requesting-tokens-converting-authorization-codes-to-access-tokens
this is the code in my controller
$response = Http::asForm()->post('http://passport-app.test/sso/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' =>env( 'CLIENT_ID'),
'client_secret' =>env( 'CLIENT_SECRET'),
'redirect_uri' =>env( 'REDIRECT_URI'),
'code' => $request->code,
]);
return $response->json();
but im getting an error
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Cannot decrypt the authorization code",
"message": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."
``

Related

microsoft graph:You cannot perform the requested operation, required scopes are missing in the token

I am calling one Microsoft graph API from my PHP application, API is https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy
my code is like below
$graph = new Graph();
$graph->setAccessToken(session('my_token'));
try{
$response = $graph->createRequest("GET", "/policies/identitySecurityDefaultsEnforcementPolicy")->execute();
}
catch(Exception $e){
dd($e);
}
$arr = $response->getBody();
dd($arr);
but it always catches exception and displays the below error
Client error: `GET https://graph.microsoft.com/v1.0/policies/identitySecurityDefaultsEnforcementPolicy` resulted in a `403 Forbidden` response:
{"error":{"code":"AccessDenied","message":"You cannot perform the requested operation, required scopes are missing in the token.","innerError":{"date":"2022-11-23T06:47:39","request-id":"9a4573c7-fd72-44ae-8ac6-8e4589cf1497","client-request-id":"9a4573c7-fd72-44ae-8ac6-8e4589cf1497"}}}
all the other Microsoft graph APIs are working well
I have also given permission to Policy.Read.All and granted admin consent to the Microsoft app I am using here for auth.
Update: when I open Microsoft's online token parser https://jwt.ms/ and parsed my token, I see the roles like
"roles": [
"Mail.ReadWrite",
"User.ReadWrite.All",
"SecurityEvents.Read.All",
"Mail.ReadBasic.All",
"Group.Read.All",
"MailboxSettings.Read",
"Group.ReadWrite.All",
"SecurityEvents.ReadWrite.All",
"User.Invite.All",
"Directory.Read.All",
"User.Read.All",
"Domain.Read.All",
"GroupMember.Read.All",
"Mail.Read",
"User.Export.All",
"IdentityRiskyUser.Read.All",
"Mail.Send",
"User.ManageIdentities.All",
"MailboxSettings.ReadWrite",
"Organization.Read.All",
"GroupMember.ReadWrite.All",
"IdentityRiskEvent.Read.All",
"Mail.ReadBasic",
"Reports.Read.All"
]
but not the Policy.Read.All
Update: Getting auth token code is
$guzzle = new \GuzzleHttp\Client();
$url = 'https://login.microsoftonline.com/'.env("TANANT_ID").'/oauth2/token?api-version=beta';
$token = json_decode($guzzle->post($url, [
'form_params' => [
'client_id' => env("CLIENT_ID"),
'client_secret' => env("CLIENT_SECRET"),
'resource' => 'https://graph.microsoft.com/',
'grant_type' => 'client_credentials',
],
])->getBody()->getContents());
// echo $token->access_token;
Session::put('my_token', $token->access_token);
When you're requesting the token, you need to supply a scope URL,
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#get-a-token
So as a basic example (this might not give the permission you need) but shows what your missing.
$guzzle = new \GuzzleHttp\Client();
$url = 'https://login.microsoftonline.com/'.env("TANANT_ID").'/oauth2/token?api-version=beta';
$token = json_decode($guzzle->post($url, [
'form_params' => [
'client_id' => env("CLIENT_ID"),
'client_secret' => env("CLIENT_SECRET"),
'resource' => 'https://graph.microsoft.com/',
'scope' => 'https://graph.microsoft.com/.default',
'grant_type' => 'client_credentials',
],
])->getBody()->getContents());
// echo $token->access_token;
Session::put('my_token', $token->access_token);
specifically notice that i have added
'scope' => 'https://graph.microsoft.com/.default', to your form params
Looks like you don't have Policy.Read.All permission , could you please cross check permission through azure portal and provide the required permission and try again.
Thanks

How to not display certain errors for Laravel 7 feature test

I have 2 methods in my feature test LoginTest.php that check for incorrect password or username.
When I run vendor/bin/phpunit I don't get any errors reported: OK (40 tests, 154 assertions)
However, I do get the following error displayed. This is expected since login is supposed to fail.
testing.ERROR: The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. {"exception":"[object] (Laravel\Passport\Exceptions\OAuthServerException(code: 10): The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. at /app/vendor/laravel/passport/src/Http/Controllers/HandlesOAuthErrors.php:26)
Here are the 2 methods that are causing the issue.
{
$this->createAccount("test#test.com");
$loginForm = array(
"grant_type" => "password",
"client_id" => "2",
"client_secret" => "lGk9EYlEHdQfXKy0EdTJ5S4Y126y0lkz0ofXiUXe",
"scope" => "*",
"username" => "test#test12.com",
"password" => $this->formData["password"]
);
$response = $this->json('POST', '/oauth/token', $loginForm);
$response->assertStatus(400);
}
public function testLoginPasswordIncorrect()
{
$this->createAccount("test#test.com");
$loginForm = array(
"grant_type" => "password",
"client_id" => "2",
"client_secret" => "lGk9EYlEHdQfXKy0EdTJ5S4Y126y0lkz0ofXiUXe",
"scope" => "*",
"username" => $this->formData["email"],
"password" => "Wrong"
);
$response = $this->json('POST', '/oauth/token', $loginForm);
$response->assertStatus(400);
}
Should I not be bothered about these displayed errors? Or is there a way to not display them?
To avoid those messages, you can use the "expectException" and "withoutExceptionHandling" methods before making the HTTP request. However, if you choose to use them, you get an exception instead of an HTTP response (Because of this, you cannot use the "assertStatus" method).
// ...
$this->withoutExceptionHandling();
$this->expectException(\Laravel\Passport\Exceptions\OAuthServerException::class);
$response = $this->json('POST', '/oauth/token', $loginForm);

Google Chat API. Can’t create space. Method not found

I'm trying to create a google chat space via making a post request to https://chat.googleapis.com/v1/spaces with Guzzle.
$scopes = [
'https://www.googleapis.com/auth/chat.spaces.create',
'https://www.googleapis.com/auth/chat.bot'
];
// create middleware
$middleware = ApplicationDefaultCredentials::getMiddleware($scopes);
$stack = HandlerStack::create();
$stack->push($middleware);
// create the HTTP client
$client = new Client([
'headers' => ['Content-Type' => 'application/json'],
'handler' => $stack,
'base_uri' => 'https://www.googleapis.com',
'auth' => 'google_auth' // authorize all requests
]);
// make the request
$response = $client->post( 'https://chat.googleapis.com/v1/spaces', [
RequestOptions::JSON => [
'name' => 'ABCDEFG',
'spaceType' => 'DIRECT_MESSAGE',
'threaded' => false,
'displayName' => 'TestSpace'
],
]);
In response I'm getting:
Client error: `POST https://chat.googleapis.com/v1/spaces` resulted in a `404 Not Found` response:
{
"error": {
"code": 404,
"message": "Method not found.",
"status": "NOT_FOUND"
}
}
But if I change the body of the request and add some new invalid fields like this:
$response = $client->post( 'https://chat.googleapis.com/v1/spaces', [
RequestOptions::JSON => [
'name' => 'ABCDEFG',
'spaceType' => 'DIRECT_MESSAGE',
'threaded' => false,
'displayName' => 'TestSpace',
'foo' => 'bar', //added invalid field
],
]);
I'm getting the next response:
Client error: `POST https://chat.googleapis.com/v1/spaces` resulted in a `400 Bad Request` response:
{
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unknown name \"foo\" at 'space': Cannot find field.",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "space",
"description": "Invalid JSON payload received. Unknown name \"foo\" at 'space': Cannot find field."
}
]
}
]
}
}
docs:
https://developers.google.com/chat/api/reference/rest/v1/spaces/create
What’s wrong with my original request?
Thanks.
The spaces.create documentation explains this at the top of the page:
Developer Preview: Available as part of the Google Workspace Developer Preview Program, which grants early access to certain features.
This means that the method is only available for users in Google's Developer Preview Program, which seems kind of like a closed beta for some developer features. The link above has a form that you can fill out to join this program, though do note that you also need to be part of the Google Cloud Partner Advantage program to apply.
In short, the method was released not long ago, and is not currently available for everyone. There's also an official blog post explaining this. It may become public in the future, so you'll have to either wait or fill out the applications to become a partner and then join the developer preview.
If you happen to be part of the program already and are still having issues you probably won't find answers among us commoners. You'd want to check out the Partner Advantage support to make sure that the features were enabled for your domain. The developer program documentation above also has a link to the issue tracker to send feedback about this API. You'll only be able to do this as a member, of course.

Not able to request token

To use Microsoft Graph, I'm trying to authenticate on behalf of the user. I'm following this tutorial, and I'm currently stuck at step 3.
When requesting the token, I receive a 400 Bad Request response:
{
"error": "invalid_scope",
"error_description": "AADSTS70011: The provided request must include a 'scope' input parameter."
}
Even though I'm including a scope parameter, this is my request:
$guzzle = new \GuzzleHttp\Client(['headers' => [
'Host' => 'https://login.microsoftonline.com',
'Content-Type' => 'application/x-www-form-urlencoded'
]
]);
$url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
$token = json_decode($guzzle->post($url, [
'form_params' => [
'client_id' => '################################',
'scope' => 'user.read%20mail.read',
'code' => $_GET['code'],
'grant_type' => 'authorization_code',
'redirect_uri' => 'https://eb3ef49e.ngrok.io/callback.php',
'client_secret' => '################'
],
])->getBody()->getContents());
What am I doing wrong?
I guess the complete error description says:
AADSTS70011: The provided request must include a 'scope' input
parameter. The provided value for the input parameter 'scope' is not
valid. The scope user.read%20mail.read is not valid. The scope
format is invalid. Scope must be in a valid URI form
<https://example/scope> or a valid Guid <guid/scope>.
If so, then Azure AD endpoint could not recognize the provided scope here. /token endpoint expects scope parameter to be specified as a space-separated list of scopes . Meaning there is no need to explicitly escape space symbol here:
'scope' => 'user.read%20mail.read'
instead specify it like this:
'scope' => 'user.read mail.read'
and and Guzzle client will do the rest of constructing the encoded body for /token endpoint

Laravel Passport Password Grant Refresh Token

Trying to wrap my head around using Laravel's Passport with mobile clients. The Password Grant type of authentication seems to be the way to go, and i have it working with my iOS app, however i can't get token refreshing to work.
When authenticating i get a token and a refresh token which i store, however when the token expires, calling the oauth/token/refresh route doesn't work. The route is using the web middleware which means my app using the api route can't access it. I'm not sure if they intended for mobile clients to never refresh or if they wanted you to roll your own refreshing? If anyone has insight on how this is supposed to work, that'd be great.
The oauth/token/refresh route is not for refreshing access tokens. It is used to refresh transient tokens, which are used when you consume your own API from your javascript.
To use your refresh_token to refresh your access token, you need to call the oauth/token route with the grant_type of refresh_token.
This is the example provided by the documentation:
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => 'the-refresh-token',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
One note about scopes, when you refresh the token, you can only obtain identical or narrower scopes than the original access token. If you attempt to get a scope that was not provided by the original access token, you will get an error.
I've done something like.
Created an endpoint for grant refresh token.
and in my controller,
public function userRefreshToken(Request $request)
{
$client = DB::table('oauth_clients')
->where('password_client', true)
->first();
$data = [
'grant_type' => 'refresh_token',
'refresh_token' => $request->refresh_token,
'client_id' => $client->id,
'client_secret' => $client->secret,
'scope' => ''
];
$request = Request::create('/oauth/token', 'POST', $data);
$content = json_decode(app()->handle($request)->getContent());
return response()->json([
'error' => false,
'data' => [
'meta' => [
'token' => $content->access_token,
'refresh_token' => $content->refresh_token,
'type' => 'Bearer'
]
]
], Response::HTTP_OK);
}

Categories