Catching 401 error when a googleapiclient build fails? - google-api-client

I am currently trying to catch an edge case when a user removes my app as a third party app without having us aware of the event. I currently don't know of any way that google would let me know if a token has been revoked until I get a google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', '{\n "error": "invalid_grant",\n "error_description": "Token has been expired or revoked."\n}')
I've tried manually 'pinging' the google client before I auth the user, but it seems a bit slower than just catching and handling the error when it occurs. I've also tried directly importing the auth error. import google.auth.exceptions.RefreshError as AuthError
Retrieving credentials:
storage = Storage(GCalUser, 'gcal_user', request.user, 'credentials')
user_credentials = storage.get()
Actual call:
try:
calendar_service = googleapiclient.discovery.build('calendar', 'v3', credentials=user_credentials)
print("Error 2: " + str(calendar_service))
except calendar_service:
pass
Looking for way to direct the user to a different page if there is an error on auth. Currently it just fails with the google.auth.exceptions.RefreshError: ('invalid_grant: Token has been expired or revoked.', '{\n "error": "invalid_grant",\n "error_description": "Token has been expired or revoked."\n}')

Fixed with explicitly fully importing the error from the module from google.auth.exceptions import RefreshError. As it turns out, the error wasn't thrown on building with the user credentials but was thrown on executing using the api.
try:
calendar_list = calendar_service.calendarList().list(pageToken=page_token, minAccessRole="writer").execute()
except RefreshError:
print("Hello debugging!")

Related

Change AWS temporary credential expiry time

I have following code in my iOS application which is integrated with Amazon Cognito identity pool. My identity pool is integrated with criipto which is a third party authentication provider. token parameter is the authentication token that I get from third party provider.
func federateToIdentityPools(token : String) async throws -> Bool{
guard let authCognitoPlugin = try Amplify.Auth.getPlugin(
for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
fatalError("Unable to get the Auth plugin")
}
do {
let result = try await authCognitoPlugin.federateToIdentityPool(
withProviderToken: token, for: .oidc("test.criipto.id"))
print("Federation successful with result: \(result.credentials.accessKeyId)")
print("Federation successful with result: \(result.credentials.secretAccessKey)")
print("Federation successful with result: \( result.credentials.expiration)")
return true
} catch {
print("Failed to federate to identity pools with error: \(error)")
return false
}
}
I get printed the credentials successfully. Now I want to change the expiration time for the credentials. For that what I did is changing the Maximum session duration from IAM roles for Authenticated role in identity pool.
But that doesn't change the credential expiration time.
Question 1 - How to change the expiration time for the temporary AWS credential that I get?
Question 2 - Is there a way that we can refresh the temporary AWS credentials when expired without federated identity provider's token?
You can go directly to the Cognito Authenticated Role within IAM and change the max session time.
Here's how to do this through the Console: https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-modify_max-session-duration
You can also update the role using the CLI (update-role) and updating the max-session-duration parameter.
You can also use the UpdateRole API and you can set this using the MaxSessionDuration parameter.
On your second question, I don't believe this will be possible as is. Maybe there could be some way to cache things, but I would avoid going down this path. The token issued from the IdP must still be valid and therefore you might want to explore how long tokens are valid from the IdP. I'm not familiar with the IdP you're using, but I would look into what's possible there.

Correct uri for DeleteAgentUser (Google Homegraph)

I'm trying to use the DeleteAgentUser of Homegraph to unlink a user with Google. I already implemented the ReportState and the correct uri for this is: https://homegraph.googleapis.com/v1/devices:reportStateAndNotification. So I thought the DeleteAgentUser has to be: https://homegraph.googleapis.com/v1/devices:deleteAgentUser but I'm getting a '404 Not Found' Error.
I tried it with:
https://homegraph.googleapis.com/v1/devices:deleteAgentUser
https://homegraph.googleapis.com/v1/deleteAgentUser
https://homegraph.googleapis.com/v1/devices:DeleteAgentUser
https://homegraph.googleapis.com/v1/DeleteAgentUser
everything with post and delete request and always getting the error.
What is the correct Homegraph uri to delete a user from Google?
Looking at the RPC defined in the public protobuf, it seems that the implementation is defined as:
rpc DeleteAgentUser(DeleteAgentUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{agent_user_id=agentUsers/**}"
};
}
So, it seems like you'd send a DELETE request to https://homegraph.googleapis.com/v1/{agent_user_id} or maybe https://homegraph.googleapis.com/v1/agentUsers/{agent_user_id} with your agent user id, and signed with your authorization token similar to Report state.

Service Account for google sheets returns not found

I am trying to read a spreadsheet using a service account (I cannot use OAuth, which works, since the process will be running on a server to periodically check sheet data)
I tried several approaches. If I follow the example using oauth I can see the sheet values. However, I need the run the script without any GUI on the background.
I have found this tutorial https://github.com/juampynr/google-spreadsheet-reader
I have created a projec, service account, added viewer role, shared the spreadsheet with the service account email. Generated the key.
It seems that the test program can connect to the google services but the moment it request the spreadsheet the end result is "404 not found".
require 'vendor/autoload.php';
$service_account_file = '/secrets/readsheetmar2019-08b737d1c1cb._portfolio_test.json';
$spreadsheet_id = '1TAWybckPrnWlQxBZh0ScDsFOvftwi2dvTBNGarSdY30';
$spreadsheet_range = '';
putenv('GOOGLE_APPLICATION_CREDENTIALS=' . $service_account_file);
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(Google_Service_Sheets::SPREADSHEETS_READONLY);
$client->fetchAccessTokenWithAssertion();
$service = new Google_Service_Sheets($client);
//added by me
if ($client->isAccessTokenExpired()) {
print "expired\n";
}else{
print "not expired\n";
}
$result = $service->spreadsheets_values->get($spreadsheet_id, $spreadsheet_range);
var_dump($result->getValues());
Error:PHP Fatal error: Uncaught exception 'Google_Service_Exception' with message '
Error 404 (Not Found)!!1
When the access token retrieved by OAuth2 is used, the Spreadsheet of $spreadsheet_id = '1TAWybckPrnWlQxBZh0ScDsFOvftwi2dvTBNGarSdY30'; can retrieve the values.
When the access token retrieved by Service Account is used, Error 404 (Not Found)!!1 is returned.
If my understanding is correct, please confirm the following points.
Confirmation points:
As a test run, please set the range $spreadsheet_range = '';.
For example, it's $spreadsheet_range = 'Sheet1'.
If the error message of The caller does not have permission is returned, please confirm as follows.
Whether the Spreadsheet of 1TAWybckPrnWlQxBZh0ScDsFOvftwi2dvTBNGarSdY30 is sharing the email of Service Account.
If you didn't share the Service Account to the Spreadsheet, please share the email of client_email in the file of readsheetmar2019-08b737d1c1cb._portfolio_test.json to the Spreadsheet you want to access.
If the error message of Google Sheets API has not been used in project ### before or it is disabled. is returned, please enable Sheets API.
If this was not the solution for your issue, I apologize.

AADSTS50034: The user account Microsoft.AzureAD.Telemetry.Diagnostics.PII does not exist in the xxx.onmicrosoft.com directory

I am trying to use graph.microsft.com apis for user invinting to the AD account.
I was able to invite but when try to get the token using
https://login.microsoftonline.com/xxxx.onmicrosoft.com/oauth2/token i am getting the above error.
I am using this key along with other required keys in the header.
[{"key":"resource","value":"https://graph.microsoft.com","description":""}]
Can you please let me know what is the issue?
Complete log.
{
"error": "invalid_grant",
"error_description": "AADSTS50034: The user account Microsoft.AzureAD.Telemetry.Diagnostics.PII does not exist in the xxxxx.onmicrosoft.com directory. To sign into this application, the account must be added to the directory.\r\nTrace ID: 5537uiy4b-4473-4cfb-b45c-1281f61e2100\r\nCorrelation ID: 8121era7-8df4-47d5-8cc5-3d2f8371029b0\r\nTimestamp: 2019-02-26 11:04:46Z",
"error_codes": [
50034
],
"timestamp": "2019-02-26 11:04:46Z",
"trace_id": "5537db4b-4473-4cfb-b45c-1281f61e2100",
"correlation_id": "812138a7-8df4-47d5-8cc5-3d2f8a1029b0"
}
On my side, I ever encountered this error. For this error, you need to check the user account that you used, the user type must be member in your Azure AD tenant, cannot be guest.

SailsJS CSRF mismatch error customize

I need to customise the error that shows up when someone did not send the CSRF code with the POST request.
So that no one will know what happened with the error and they will not even try to hack in to the CSRF mechanism.
Hope this is clear
For now Sails.js CSRF hook uses res.forbidden() function to handle wrong CSRF token.
It uses it with this message:
return res.forbidden("CSRF mismatch");
So you could rewrite this response by placing a new file with name forbidden.js into /api/responses
Actually you cound copy this one: https://github.com/balderdashy/sails/blob/master/lib/hooks/responses/defaults/forbidden.js
And add condition to check data before production mode check:
...
else sails.log.verbose('Sending 403 ("Forbidden") response');
if (data == 'CSRF mismatch') {
//Return another response for example:
return res.jsonx(500, {/* data here */});
}
// Only include errors in response if application environment
// is not set to 'production'. In production, we shouldn't
// send back any identifying information about errors.
if (sails.config.environment === 'production') {
...
Anyway as long as you will use development mode for sails. You will see all errors when getting 500 or any other error from sails. But in production mode all error messages will be hidden. And your users wouldn't get any error details. Except of error code.
So in production mode without any changes you will get only HTTP 403 code.