i use passport in laravel and after user verification i want to generate a token for them with refresh token . for get refresh token i have to send curl request with password grant_type . after generate access token i want to get Password Grant Clientfrom database and pass it to my curl body . i fount this code snippet:
$tokenId = (new Parser(new JoseEncoder()))->parse($token)->claims()->get('jti');
$client = \Laravel\Passport\Token::find($tokenId)->client;
and the problem result of client variable is Personal Access Client not Password Grant Client and get this error because of its personal type:
{
"error": "invalid_client",
"error_description": "Client authentication failed",
"message": "Client authentication failed"
}
this is my code:
$token = $user->createToken(Config::get('auth.guards.api.token_name'))->accessToken;
$tokenId = (new Parser(new JoseEncoder()))->parse($token)->claims()->get('jti');
$client = \Laravel\Passport\Token::find($tokenId)->client;
$http = new \GuzzleHttp\Client();
try {
$response = $http->request('POST', url("/oauth/token"), [
'form_params' => [
'grant_type' => 'password',
'client_id' => $oClient->id,
'client_secret' => $oClient->secret,
'username' => $username,
'password' => $password,
'scope' => '*',
],
]);
} catch (\Exception $exception) {
}
how can i deal with this?
For obtaining the client_id and client_secret for Password Grant Client you need to run the following command on your authorization server (OAuth server) as stated here https://laravel.com/docs/9.x/passport#creating-a-password-grant-client
php artisan passport:client --password
The above command is not necessary to run if you already ran passport:install. The easiest way is to check your oauth_clients table for the column password_client there should be a row that has this value set to 1 (enabled).
It seems from your question that you are trying to obtain the client_id and client_secret programmatically from your client. This is not the correct way of doing it.
Basically after you run the above command to generate your client_id and client_secret you need to hard code them in your .env and use them in you CURL such as:
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => env('OAUTH_CLIENT_ID'),
'client_secret' => env('OAUTH_CLIENT_SECRET'),
'username' => $username,
'password' => $password,
'scope' => '*',
]);
return $response->json();
You can obtain your client_id and client_secret from the oauth_clients table. Just make sure to copy the values where the password_client column is set to 1.
There should not be any security concern if your client is storing these credentials in the backend and doing the CURL from the backend.
In the case you are trying to do this from a mobile app and you might not have a way to securely store the client_id and client_secret. In this case you should not be using the Password Grant Client flow but instead the Authorization Code Grant with PKCE: https://laravel.com/docs/9.x/passport#code-grant-pkce
Related
I want to configure my Symfony4 application to read and send e-mails using the msgraph-sdk-php library.
My app would be reading and sending e-mail from a single account, whose password I don't want to expose to my app's users. Thus, I wouldn't be using OAuth for login.
My first experience was this piece of code (to retrieve mailbox user profile):
<?php
namespace App\Graph;
use Microsoft\Graph\Exception\GraphException;
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model\User;
class GraphService
{
function sentTestMessage() {
$userId = "************************************";
$tenantId = "************************************";
$clientId = "************************************";
$clientSecret = "***************************";
$guzzle = new \GuzzleHttp\Client();
$url = 'https://login.microsoftonline.com/' . $tenantId . '/oauth2/token?api-version=1.0';
$token = json_decode($guzzle->post($url, [
'form_params' => [
'client_id' => $clientId,
'client_secret' => $clientSecret,
'resource' => 'https://graph.microsoft.com/',
'grant_type' => 'client_credentials',
],
])->getBody()->getContents());
$accessToken = $token->access_token;
$graph = new Graph();
$graph->setAccessToken($accessToken);
$user=new \stdClass();
try {
$user = $graph->createRequest("GET", "/users/".$userId)
->setReturnType(User::class)
->execute();
} catch (GraphException $e) {
$user->getGivenName=$e->getMessage();
}
return "Hello, I am $user->getGivenName() ";
}
}
But then Symfony shows me an exception page with this message:
Client error: GET https://graph.microsoft.com/v1.0/users/... resulted in a 403 Forbidden response:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the ope (truncated...)
Now the same query works when run in https://developer.microsoft.com/en-us/graph/graph-explorer with the same user logged in.
These are the permissions I gave the app:
What should I do to overcome the problem above described?
You used client credentials flow to get access token in your code, so you need application permission instead of delegated permission.
I have to encrypt user table data using aws kms encryption, i have refreed following code that doesnt work for me, throwing error 'The security token included in the request is invalid.
AWS HTTP error: Client error: POST https://kms.us-east-1.amazonaws.com resulted in a 400 Bad Request response:' can someone help me out?
my code is
<?php
use Aws\Kms\KmsClient;
// Somewhere in the controller or model
$this->load->config('aws');
// Not needed for EC2 instance role based authorization - for my local instance only
$key = $this->config->item('aws_s3_access_key');
$secret = $this->config->item('aws_s3_secret_key');
$orig = 'encrypt me please...';
$cryptic = 'CiD/AT9S0xQbpFXHDdw7Mq42htuEVj0vwvZzfR+9GRZCahKbAQEBAgB4/wE/UtMUG6RVxw3cOzKuNobbhFY9L8L2c30fvRkWQmoAAAByMHAGCSqGSIb3DQEHBqBjMGECAQAwXAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAxvNDVWPh6W4STdWakCARCAL/nzjIDZ8uQWAMWI1VBoNPt+TCe9qZMMbY1d1PnVjlJGa/BcVdAyN9KruzEOcFl6';
// Testing the encrypt and decrypt cycle
$kms = KmsClient::factory([
'credentials' => [
'key' => $key,
'secret' => $secret,
],
'region' => 'us-east-1',
]);
// Encrypt - should match $cryptic
$result = $kms->encrypt([
'KeyId' => 'alias/argus-db-crypt-local',
'Plaintext' => $orig,
]);
var_dump(base64_encode($result->get('CiphertextBlob')));
// Decrypt - should match $orig
$result = $kms->decrypt([
'CiphertextBlob' => base64_decode($cryptic),
]);
var_dump($result->get('Plaintext'));
You must be using an incorrect ACCESS/SECRET key pair.
Try to go to the security credentials on your account page: Click on your name in the top right corner -> My security credentials
Then generate access keys over there and use those access keys in your .env file
I'm currently trying to implement a way to synchronize my PHP App calendar with the Outlook calendar of my clients, using Azure API.
I use OAuth2 and the custom Microsoft provider by Steven Maguire.
I currently run in an issue where I get an error in my response :
{"error":"unsupported_grant_type","error_description":"The provided value for the input parameter 'grant_type' is not valid. Expected values are the following: 'authorization_code', 'refresh_token'."}
I'm having trouble understanding why the grant_type password is not supported, even though it says on the documentation of Azure that it is.
The request looks like this :
client_id=44bef79b-**********************&client_secret=H****************&redirect_uri=https%3A%2F%2F192.168.1.123%2Fmapeyral%2Fcalendarsync.php&grant_type=password&username=******************&password=***********&scope=openid%20profile%20offline_access%20Calendars.ReadWrite
The Authorize url used is : https://login.live.com/oauth20_token.srf
as defined in the Steven Maguire provider.
The header contains the content-type application/x-www-form-urlencoded (I've seen a lot of post where this was what caused the error).
Some of my code :
$this->provider = new Microsoft([
'clientId' => MicrosoftGraphConstants::CLIENT_ID,
'clientSecret' => MicrosoftGraphConstants::CLIENT_SECRET,
'redirectUri' => MicrosoftGraphConstants::REDIRECT_URI,
'urlAuthorize' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::AUTHORIZE_ENDPOINT,
'urlAccessToken' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => MicrosoftGraphConstants::RESOURCE_ID,
'scope' => MicrosoftGraphConstants::SCOPES
]);
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_GET['code']))
{
// Try getting access token from Database
$workingAccount = $GLOBALS['AppUI']->getState('working_account');
if (isset($workingAccount))
{
// DB access
$DB = new DatabaseConnection();
$dbAccess = $DB->getConnection();
$contactData = DBUserUtils::getContactDataFromEmail($GLOBALS['AppUI']->getState('working_account'), $dbAccess);
// If at least one user contact found
if (!is_null($contactData))
{
// If has refresh token => fill session variables using refresh token
if (!is_null($contactData['contact_refreshToken']))
{
log_msg('debug.log', 'Has refresh token');
$GLOBALS['AppUI']->setState('preferred_username', $contactData['contact_email']);
$GLOBALS['AppUI']->setState('given_name', $contactData['contact_first_name']." ".$contactData['contact_last_name']);
// Get new tokens
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $contactData['contact_refreshToken']
]);
// Update tokens and DB
$GLOBALS['AppUI']->setState('refresh_token', $newAccessToken->getRefreshToken());
$GLOBALS['AppUI']->setState('access_token', $newAccessToken->getToken());
DBOAuthUtils::updateTokenForUser($contactData['contact_id'], $GLOBALS['AppUI']->getState('refresh_token'), $dbAccess);
$this->redirectTo($redirectURL);
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
function getAccessToken(){
$accessToken = $this->provider->getAccessToken('password', [
'username' => '*************',
'password' => '********',
'scope' => MicrosoftGraphConstants::SCOPES
]);
}
During the first try it doesn't pass the if (isset($workingAccount)) condition (as expected) and go straight to the last else.
Code is a bit ugly for now but I don't think it has an impact on my problem.
Any help would be appreciated !
Thanks
Edit : added code
That helped me, the problem was that I need to use Azure Active Directory and not Azure AD 2.0.
Problem solved !
I have installed laravel 5.3 and passport pakage.
I followed the documentaition step by step
I can use the following route POST /oauth/token with the following parameters
username
password
client_secret
grant_type
client_id
and I get the following response
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "access token here",
"refresh_token": "refresh token here"
}
then I request GET /api/user
with the following header
Authorization = "Bearer access token here"
accept = application/json (optional)
and this is work fine and so all apis.
the problem I have is the user who I authinticated and entered his username and password in the first request and return me back the access token is a user I have created from laravel web view /register
How can I create new user or register new user from the api route file
like POST /api/register
the user at first time need to register to be authinticated after that.
Should I create this route without oauth to register then if success the registration he request POST /oauth/token to be authinticated or what?
Am I missing something ??
update
the clent_secret is it right to be constant in all users requests or each user should have diffrent clent_secret, and if it is how to create aclent secret if it neaded to authinticate user ?
The fastest way to do this is adding an exception to your verifyCsrfToken.php class
protected $except = [
'register'
];
Then you can post to your register model, and afterwards accessing this account with oauth/token.
If i understand your question correctly, you want to register new user and get token after registration from /oauth/token. For this you can use a proxy. I have used something similar and i followed the following steps. This works for both Login and Register
Register the user and send a HTTP request to /oauth/token endpoint from your register method
public function register(RegisterRequest $request)
{
$user = User::create($request->all());
$response = $this->authenticationProxy->attemptLogin($request->email, $request->password);
return response()->json(compact('response', 'user'), 201);
}
Then in your proxy class, call the /oauth/token
public function attemptLogin($email, $password)
{
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => env('CLIENT_ID'),
'client_secret' => env('CLIENT_SECRET'),
'username' => $email,
'password' => $password,
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
}
Hope this helps. You can use similar approach for login as well.
In my PHP application, users provide their own Facebook Application ID and Application Secret. I need to validate them and display nice error if they are invalid.
I already found a nice way to do it. I can make a request to https://graph.facebook.com/oauth/access_token?client_id=123456&client_secret=abcdefg&grant_type=client_credentials
If credentials are invalid, the response is as follows:
{
"error": {
"message": "Error validating application. Cannot get application info due to a system error.",
"type": "OAuthException",
"code": 101,
"fbtrace_id": "D8oHjJoc2Nc"
}
}
I'm confused about the ways to do it with PHP SDK. There's a neat get() method to make such a request, but I'm not sure how to send request without authorizing the application. This is what I did:
$app = new Facebook\FacebookApp( $app_id, $app_secret );
$access_token = $app->getAccessToken();
$query = http_build_query([
'client_id' => $app_id,
'client_secret' => $app_secret,
'grant_type' => 'client_credentials',
]);
$facebook = new Facebook\Facebook( [
'app_id' => $app_id,
'app_secret' => $app_secret,
'default_graph_version' => '2.5',
] );
$response = $facebook->get( '/oauth/access_token?' . $query, $access_token );
I'm getting the following error:
Unknown path components: /oauth/access_token
But even if it worked, it's strange to call it with any sender credentials. Is it possible to make an "anonymous" Facebook request with PHP SDK?
The SDK implicitly adds the API version number specified to the path in -> get(), so I think that's causing your error here because the underlying call is being made to /2.5/oauth/access_token (fails for me in a browser)
It should be /v2.5/oauth/access_token (works for me in a browser)
Update default_graph_version to v2.5 and try that