I would like to send email messages with our corporate emails provided by Gmail. In order to do that, I would like to use Gmail API with rest commands (basically launched with a php procedural code, for legacy purpose).
I have that code :
I go to this url :
// https://accounts.google.com/o/oauth2/auth?client_id=my_client_id&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/gmail.send&response_type=code
// and obtain a token like that : 4/1AX4XfWgmW0ZdxXpJn8YzkVeDs3oXZUHyJcR7abE2TuqQrcmo4c1W02ALD4I
/*
echo GoogleAuthCurl("GET", '', array(
'client_id' => $GOOGLE_CLIENT_ID,
'redirect_uri'=>'urn:ietf:wg:oauth:2.0:oob',
'scope' => 'https://www.googleapis.com/auth/gmail.send',
'response_type' => 'code'
), array());
then I can use requests in curl for getting my access token :
curl \
--request POST \
--data "code=[Authentcation code from authorization link]&client_id=[Application Client Id]&client_secret=[Application Client Secret]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code" \
https://accounts.google.com/o/oauth2/token */
$tokenJson = json_decode( GoogleTokenCurl("POST", '', array(), array(
'code' => '4/1AX4XfWiEWngRngF7qryjtkcOG1otVtisYpjHnej1E54Pujcrchef8REvdt0',
'client_id' => $GOOGLE_CLIENT_ID,
'client_secret' => $GOOGLE_CLIENT_SECRET,
'redirect_uri'=>'urn:ietf:wg:oauth:2.0:oob',
'grant_type' => 'authorization_code'
)
));
print_r($tokenJson);
This far, I've got food for my authorization header. My issue is in the first step (with the consent asked to user). I wish i can do this step without putting my url in the browser, validate two screens to grant access before getting the authorization code.
I'm also interested in advices to create gmail messages with rest requests driven by curl. I found postman collection about all actions gmail api can do, but one or two call examples wouldn't do harm ;)
thanks !
In the current state, by the method you are using, &response_type=code, you need two calls to the OAuth client to get the access token. You can find an example of how to handle it just using HTTP/REST requests here.
In any case, you could use Google API Client Library for PHP. Allows you to handle the OAuth authentication flow, only needing one interaction to get the token.
You can find a full example on how this works here, notice that this example uses the Drive API, if you want to use it within the Gmail API, you can check Gmail API PHP library.
Documentation:
PHP Gmail API
OAuth 2.0 to Access Google APIs
Related
I want to use the Microsoft Graph API on my application (which is actually on development).
I use fullcalendar js on my application (laravel 8) and when a user create an event on my application I want the same event create on his outlook calendar.
I want that the user connected on my application has only the right to access his outlook calendar (not all organization users calendar). In order to restrict this I understand that I have to use delegated autorizations and not applications autorizations.
First I would like to get an access token in order to use the API.
To do this I use oauth2 and guzzle :
$url = 'https://login.microsoftonline.com/' . env('MS_TENANT_ID'). '/oauth2/v2.0/token?api-version=1.0';
$tokenCall = Http::asForm()->post($url, [
'grant_type' => 'client_credentials',
'client_id' => env('MS_CLIENT_ID'),
'client_secret' => env('MS_CLIENT_SECRET'),
'scope' => 'https://graph.microsoft.com/.default',
'username' => 'xxx.xxx#xxx.com',
'password' => 'xxxxxxxx',
]);
$accessToken = json_decode($tokenCall->getBody()->getContents());
I obtain a token but when I inspect it with jwt.io, it appears that I haven't scopes in it (scp).
Do you know why it doesn't appears?
EDIT:
It appears that I use an application authentication and not a delegated authentication (for user).
So I change the 'grant_type' parameters for 'password' instead of 'client_credentials'.
But it throws me another error :
invalid_grant
AADSTS65001: The user or administrator has not consented to use the application with ID 'xxxxxxxxxxxxxxxxxxxxxxxx' named 'Graph PHP'. Send an interactive authorization request for this user and resource.
I read that in an delegated authentication I have to call the authorize point before the token point.
To do this I have to define a Redirect URI on my application on Azure. Unfortunately I made development on a local server (not localhost) which haven't SSL. Azure dosen't allow the Redirect URI to be on http except for localhost...
Is someone have already face this problem?
Hello all i have created with google oauth api an easy way to validate an ID token signature for debugging by using the tokeninfo endpoint.
To validate an ID token using the tokeninfo endpoint, i make an HTTPS POST or GET request to the endpoint, and pass my ID token in the id_token parameter. For example, to validate the token "XYZ123", make the following GET request:
https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123
If the token is properly signed and has the appropriate values I got an HTTP 200 response (i follow this guide https://developers.google.com/identity/sign-in/web/backend-auth)
What is the alternative choice within apple? Any recommendations on how to fix the exact same thing for apple?
Here is an example of my code:
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://oauth2.googleapis.com/tokeninfo?id_token=' . $request->input('token'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$response = curl_exec($curl);
curl_close($curl);
$responseDecoded = json_decode($response);
if (isset($responseDecoded->error)) //FAILED TO GOOGLE AUTHENTICATED
{
if ($responseDecoded->error=='invalid_token')
{
return response()->json(['status' => 'fail', 'message'=>'invalid_token']);
}
}
A key thing to understand here:
There are a myriad of ways for users to sign in - one of them is Apple - they come and go - see the Curity Authenticators Page to get a feel for this.
Protecting your data should work the same in all cases.
So if you base your data protection around Apple it will just not work for people who do not use Apple to sign in and you are restricting your possibilities.
Here is how the solution should work:
Your UIs and APIs talk to an Authorization Server (AS)
The AS manages the connection to Apple and the 25 other possible authentication methods
Every time you add a new authentication option, zero code needs to change in any of your UIs and APIs
Your UI and API code remains simple and portable over time
To summarize, I would recommend your apps talk to Google OAuth2 - which helps to protect your data, whereas Apple should play a smaller role of being an authentication method - Google should talk to Apple for you.
At Curity we provide a Sign in with Apple capability. Our main mission is around protecting data though ...
ID TOKEN VALIDATION
If this is received in a browser response it should be validated by the app. This usually involves downloading token signing public keys from the Authorization Server. Some providers may give you an endpoint that does this as in the Google case.
Apple provide some (non standard) behavior as in this link to do an equivalent thing.
But coding this in your app is likely to lead to further problems later, when you try to implement authorization. Note also that an ID token should not be used to protect data in APIs - use access tokens instead.
Is it possible to allow a client to connect to the API ONLY with a google apps domain email address? Users often have their own gmail session active and we need to ensure that they can only connect to the api using our Google Apps Domain email.
For now the only solution has been that we disconnect them when they return from the auth steps if their email address doesnt contain our domain, with an error message telling them they need to follow the steps again using their [domain].com email address, which is far less than ideal. Can the domain be specified somewhere in the scopes or api console for example?
[Google API PHP Client]
I found a hacky solution, describing briefly for those who may need smth similiar:
If you add the login_hint parameter with the email address (in this case with Google Apps account, with our own domain) it bypasses the initial login page and if any other google sessions are available bypasses them as well. I didn't find this behavior described in the documentation, nor did I find the ability to add this parameter in the google-api-php-client. I added a method in the Google_Client.php file to allow the ability to add the login_hint parameter:
public function setLoginHint($loginHint) {
global $apiConfig;
$apiConfig['login_hint'] = $loginHint;
self::$auth->login_hint = $loginHint;
}
And the parameter to the authenticate method in Google_Oauth2.php:
$request = Google_Client::$io->makeRequest(new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), array(
'code' => $code,
'grant_type' => 'authorization_code',
'redirect_uri' => $this->redirectUri,
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'login_hint' => $this->loginHint
)));
Then I can call the method using the user's Google Apps email address during authentication:
$client->setLoginHint("user#mydomain.com")
If there was something built in that I didnt find in the docs or searches please let me know. By the way, I thought Google API guys were keeping an eye on SO for questions such as these, echo echo...
I'm using OAuth with Federated Login (Hybrid Protocol) to allow my users to login once using openID (which works great), and authenticate with the Google Data API at the same time.
The Zend_GData library was giving me a headache, so on the suggestion of someone here on SO I switched to LightOpenID.
The openID part works great, and thanks to this tip I'm able to add the OAuth extension and receive a response like this:
http://www.example.com/checkauth
?openid.ns=http://specs.openid.net/auth/2.0
&openid.mode=id_res
&openid.op_endpoint=https://www.google.com/accounts/o8/ud
&openid.response_nonce=2009-01-17T00:11:20ZlJAgbeXUfSSSEA
&openid.return_to=http://www.example.com/checkauth
&openid.assoc_handle=AOQobUeYs1o3pBTDPsLFdA9AcGKlH
&openid.signed=op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle,ns.ext2,ext2.consumer,ext2.scope,ext2.request_token
&openid.sig=oPvRr++f6%2ul/2ah2nOTg=
&openid.identity=https://www.google.com/accounts/o8/id/id=AItOawl27F2M92ry4jTdjiVx06tuFNA
&openid.claimed_id=https://www.google.com/accounts/o8/id/id=AItOawl27F2M92ry4jTdjiVx06tuFNA
&openid.ns.oauth=http://specs.openid.net/extensions/oauth/1.0
&openid.oauth.scope=http://docs.google.com/feeds/+http://spreadsheets.google.com/feeds/+http://sandbox.gmodules.com/api/
&openid.oauth.request_token=1/fVr0jVubFA83GjYUA
According to the documentation, openid.oauth.request_token is an authorized request token, so it seems I don't need to do the OAuthAuthorizeToken request. All is good so far, but now I need to exchange this request token for an access token and token secret.
Since I have no idea how to generate the OAuth nonce and signatures, I employ the OAuthSimple library for php. Problem is, the code required looks like this:
// Build the request-URL...
$result = $oauth->sign(array(
'path' => 'https://www.google.com/accounts/OAuthGetAccessToken',
'parameters' => array(
'oauth_verifier' => $_GET['oauth_verifier'],
'oauth_token' => $_GET['oauth_token']),
'signatures' => $signatures));
It needs an oauth_verifier value, which you would receive along with the request token with a normal OAuth request. I'm not sure if it's the OAuthSimple library that errors out when trying to omit that or if it's a Google requirement, but it doesn't work.
SO, can someone spot something I'm doing wrong here?
There's nothing wrong. Actually, when you do an Hybrid process, the verifier isn't send, simply because you don't need it.
So in your code, just set verifier to NULL, and it should work just fine, as long as there's no problems somewhere else.
I am trying to write a small webapp that pulls data from Yammer. I have to go through Yammer's OAuth bridge to access their data. I tried using the Oauth php library and do the 3 way handshake. But at the last step, I get an error stating I have an invalid OAuth Signature.
Here are the series of steps:
The first part involves getting the request Token URL and these are the query parameters that I pass.
[oauth_version] => 1.0
[oauth_nonce] => 4e495b6a5864f5a0a51fecbca9bf3c4b
[oauth_timestamp] => 1256105827
[oauth_consumer_key] => my_consumer_key
[oauth_signature_method] => HMAC-SHA1
[oauth_signature] => FML2eacPNH6HIGxJXnhwQUHPeOY=
Once this step is complete, I get the request Token as follows:
[oauth_token] => 6aMcbRK5wMqHgZQsdfsd
[oauth_token_secret] => ro8AJxZ67sUDoiOTk8sl4V3js0uyof1uPJVB14asdfs
[oauth_callback_confirmed] => true
I then try to authorize the given token and token secret by passing the parameters to the authorize url.It takes me to Yammer's authentication page where I have allow my app to talk to Yammer.
Yammer then gives me a 4 digit code that I have to put back into my application which then tries to acquire the permanent access token. I pass the following information to the access token URL:
[oauth_version] => 1.0
[oauth_nonce] => 52b22495ecd9eba277c1ce6b97b00fdc
[oauth_timestamp] => 1256106815
[oauth_consumer_key] => myconsumerkey
[callback_token] => 61A7
[oauth_token] => 6aMcbRK5wMqHgZQsdfsd
[oauth_token_secret] => ro8AJxZ67sUDoiOTk8sl4V3js0uyof1uPJVB14asdfs
[oauth_callback_confirmed] => true
[oauth_signature_method] => HMAC-SHA1
[oauth_signature] => V9YcMDq2rP7OiZTK1k5kb/otMzA=
Here I am supposed to receive the Oauth Permanent access token, but instead I get a Invalid Oauth signature. I dont know what I am doing wrong. I use the same signaures to sign the request. Should I sign the request using the new token and secret? I tried that as well but to no avail. I even tried implementing this in java using signpost library and got stuck at the exact same place. Help Help!!
The callback_token was something Yammer introduced in response to an OAuth security advisory earlier this year. When OAuth 1.0a was released, it was instead named oauth_verifier. However, it's not unlikely that Yammer still supports their workaround but rename it and try again to be sure.
Also, the below is information from the Yammer Development Network yesterday:
Tomorrow we will be releasing some
changes to the Yammer API to
facilitate user network switching on
API clients. Most of the change is in
the OAuth Access Tokens call which
allows you to generate pre-authorized
OAuth access tokens for a given user.
One token will be generated for each
network they are in and your clients
switch networks by sending an API
request signed with the appropriate
token for that network.
I'm assuming that Yammer OAuth libraries might need to be updated per this change. I haven't taken a look at it yet.
Edit: My python-yammer-oauth library still works despite Yammer having changed things on their side.
Edit2: Could you try using signature method PLAINTEXT instead of HMAC-SHA1? I've had problems with Yammer and HMAC-SHA1.
I tried by using PLAINTEXT.. but for this method its giving me the same "Invalid OAuth signature" error even for requesting the token.
So is it possible to generate the access token we use HMAC-SHA1 and for accessing the actual API method i.e. for posting the message.. we use PLAINTEXT?
just found the problem!
I had forgotten to add an ampersand ("&") at the end of CONSUMER_SECRET. Perhaps this is your issue as well?