Google Oauth Cross-client auth with javascript: Token has expired - javascript

I've been dealing all day with this problem and I just can't figure out what's wrong.
I have an application using the Google Api client for javascript which is working with no problems. Now I want to do something on the server side, so after researching for a bit, found that the way to go would be to use the token on the client side with setAccessToken method in the backend.
So I try sending my token object as JSON (using JSON.stringify(gapi.auth.getToken()) ) and once I try doing an API call on the backend that requires auth, I get the following error:
The OAuth 2.0 access token has expired, and a refresh token is not available. Refresh tokens are not returned for responses that were auto-approved.
So, a little puzzled, I try veryfing the token using curl on google's endpoint, which returns the following
{
"issued_to": "client_id",
"audience": "client_id",
"user_id": "user_id",
"scope": "https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me",
"expires_in": 1465,
"email": "user_email",
"verified_email": true,
"access_type": "online"
}
So I know the token is fine and valid. The way my code is setup is as follows (redacted for:
<?php
// The token JSON is not inline, it comes from another source directly from the client side, but this is how it looks
$token_json = '{"state":"","access_token":"TOTALLY_VALID_ACCESS_TOKEN","token_type":"Bearer","expires_in":"3600","scope":"https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me","client_id":"CLIENT_ID","g_user_cookie_policy":"single_host_origin","cookie_policy":"single_host_origin","response_type":"token","issued_at":"1415583001","expires_at":"1415586601","g-oauth-window":{},"status":{"google_logged_in":false,"signed_in":true,"method":"PROMPT"}}';
$OAUTH2_CLIENT_ID = 'CLIENT_ID';
$OAUTH2_CLIENT_SECRET = 'CLIENT_SECRET';
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setAccessToken($token_json);
$youtube = new Google_Service_YouTube($client);
try{
/* Random code goes here */
// Auth Exception here.
$insertRequest = $youtube->videos->insert("status,snippet", $video);
} catch (Google_Exception $e) {
var_dump($e->getMessage());
}
Do I need to set up offline access or something? I have the requirement that the login process must be in javascript, so no chance of recreating the login flow from the backend.
Is there anything I'm missing?

Well, if someone else stumbles into this:
Apparently, sharing tokens directly is not the way to go, since the different API wrappers handle tokens differently. What you have to do is pass the one-time code to PHP and use the following to acquire an access token
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
// Couldn't find this anywhere in the docs, but it's required. If you don't pass this, you will get an Origin Mismatch error.
$client->setRedirectUri('postmessage');
// Get this from javascript
$client->authenticate($ONE_TIME_CODE);
// Optionally, you might want to retrieve the token and save it somewhere else e.g. the session, as the code is only good for a single use.
$_SESSION['token'] = $client->getAccessToken();
Also, from JS you NEED to specify you require this one-time code besides the JS token, which I couldn't find documented anywhere else as well.
Example settings, for gapi.auth.authorize
{
client_id: CLIENT_ID
scope: APP_SCOPES
cookie_policy: 'single_host_origin'
response_type: 'code token'
immediate: true
}

Thanks a lot, Moustached. I've also spent the whole day trying to solve that. However, I found not that obvious what is one-time code and how to get it, so I decided to provide my code here in case someone else face the same problem:
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://apis.google.com/js/platform.js?onload=onGoogleAPILoad" async defer></script>
<script>
$(document).ready(function() {
var auth2;
window.onGoogleAPILoad = function() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({ client_id: 'CLIENT_ID', scope: 'profile' });
});
};
$('button').on('click', function() {
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(function(response) {
$.ajax({
method: 'POST',
url: '/auth/signin',
success: onAuthSuccess = function(response) {
// check response from your server and reload page if succeed
},
data: { code: response.code }
});
});
});
});
</script>
</head>
<body>
<button>Sign In</button>
</body>
</html>
and for back-end the code is almost the same:
$client = new Google_Client();
$client->setClientId('CLIENT_ID');
$client->setClientSecret('CLIENT_SECRET');
$client->setRedirectUri('postmessage');
$client->authenticate($code); // here is one-time code
$plus = new Google_Service_Plus($client);
$user = $plus->people->get('me');
// $user is in array, containing now id, name, etc.
Here is an article on that topic.

Related

403 error in calling DerivativeApi of Autodesk Forge

Autodesk Forge's DerivativeApi is not working with my client id and secret. Apis returns unauthorized error, { statusCode: 403, statusMessage: 'Unauthorized’ }.
But they works with the sample's client id/secret (from https://github.com/Autodesk-Forge/forge-api-nodejs-client/blob/master/samples/dmSample.js).
Is there any limitation for calling DerivativeApi (for translating) with free account? or should I do something?
Here is the sample code...
var ForgeSDK = require('forge-apis');
// TODO - insert your CLIENT_ID and CLIENT_SECRET
// Below id/secret from the sample are working, but mine is not.
var CLIENT_ID = 'wmizntnpzCJxPGF9lxsIiTZGbGO2cJqw',
CLIENT_SECRET = 'g5IPJwvhOHcrdbFy';
var derivativesApi = new ForgeSDK.DerivativesApi();
// Initialize the 2-legged oauth2 client
var oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(CLIENT_ID, CLIENT_SECRET,
['data:write', 'data:read', 'bucket:read', 'bucket:update', 'bucket:create'], true);
function defaultHandleError(err) {
console.error('\x1b[31m Error:', err, '\x1b[0m');
}
oAuth2TwoLegged.authenticate().then(function (credentials) {
console.log("**** Got Credentials", credentials);
derivativesApi.getFormats({}, oAuth2TwoLegged, oAuth2TwoLegged.getCredentials()).then(res => {
console.log(res);
}, defaultHandleError);
}, defaultHandleError);
Thanks
First, and extremely important, NEVER share your ID & Secret. If the above is your correct one, please create a new secret (to invalidate this).
Now the ID & Secret should work for any sample, just make sure you activated the APIs for it. On your app, select Model Derivative API on the screen, if not available, please review this article.
Finally, the code sample above is not actually calling Model Derivative. If so, note that files uploaded into one account are not accessible from other accounts, and URNs are unique.

Keycloak JavaScript API to get current logged in user

We plan to use keycloak to secure a bunch of web apps, some written in Java, some in JavaScript (with React).
After the user is logged in by keycloak, each of those web apps needs to retrieve the user that is logged in and the realm/client roles that the user has.
For Java apps, we tried the keycloak Java API (request -> KeycloakSecurityContext -> getIdToken -> getPreferredUsername/getOtherClaims). They seem to work fine
For JavaScript apps, we tried the following code, but could not get Keycloak to init successfully (Note this is in web app code after the user is already authenticated by keycloak, the app is only trying to retrieve who logged in with what roles):
var kc = Keycloak({
url: 'https://135.112.123.194:8666/auth',
realm: 'oneRealm',
clientId: 'main'
});
//this does not work as it can't find the keycloak.json file under WEB-INF
//var kc = Keycloak('./keycloak.json');
kc.init().success(function () {
console.log("kc.idToken.preferred_username: " + kc.idToken.preferred_username);
alert(JSON.stringify(kc.tokenParsed));
var authenticatedUser = kc.idTokenParsed.name;
console.log(authenticatedUser);
}).error(function () {
window.location.reload();
});
I assume it would be fairly common that web apps need to retrieve current user info. Anyone knows why the above code didn't work?
Thanks.
<script src="http://localhost:8080/auth/js/keycloak.js" type="text/javascript"></script>
<script type="text/javascript">
const keycloak = Keycloak({
"realm": "yourRealm",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "yourRealm/keep it default",
"public-client": true,
"confidential-port": 0,
"url": 'http://localhost:8080/auth',
"clientId": 'yourClientId',
"enable-cors": true
});
const loadData = () => {
console.log(keycloak.subject);
if (keycloak.idToken) {
document.location.href = "?user="+keycloak.idTokenParsed.preferred_username;
console.log('IDToken');
console.log(keycloak.idTokenParsed.preferred_username);
console.log(keycloak.idTokenParsed.email);
console.log(keycloak.idTokenParsed.name);
console.log(keycloak.idTokenParsed.given_name);
console.log(keycloak.idTokenParsed.family_name);
} else {
keycloak.loadUserProfile(function() {
console.log('Account Service');
console.log(keycloak.profile.username);
console.log(keycloak.profile.email);
console.log(keycloak.profile.firstName + ' ' + keycloak.profile.lastName);
console.log(keycloak.profile.firstName);
console.log(keycloak.profile.lastName);
}, function() {
console.log('Failed to retrieve user details. Please enable claims or account role');
});
}
};
const loadFailure = () => {
console.log('Failed to load data. Check console log');
};
const reloadData = () => {
keycloak.updateToken(10)
.success(loadData)
.error(() => {
console.log('Failed to load data. User is logged out.');
});
}
keycloak.init({ onLoad: 'login-required' }).success(reloadData);
</script>
simple javascript client authentication no frameworks.
for people who are still looking...
Your code asks the Keycloak client library to initialize, but it doesn't perform a login of the user or a check if the user is already logged in.
Please see the manual for details: http://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter
What your probably want to do:
Add check-sso to the init to check if the user is logged in and to retrieve the credentials keycloak.init({ onLoad: 'check-sso' ... }). You might even use login-required.
Make sure that you register a separate client for the front-end. While the Java backend client is of type confidential (or bearer only), the JavaScript client is of type public.
You find a very minimal example here: https://github.com/ahus1/keycloak-dropwizard-integration/blob/master/keycloak-dropwizard-bearer/src/main/resources/assets/ajax/app.js
Alternatively you can register a callback for onAuthSuccess to be notified once the user information has been retrieved.
Once you use Keycloak in the front-end, you will soon want to look in bearer tokens when calling REST resources in the backend.
You might have solved the problem by this time. I hope this answer help rest of the people in trouble.
when you use JavaScript Adopter
Below javascript should be added in of html page.
<script src="http://localhost:8080/auth/js/keycloak.js"></script>
<script>
/* If the keycloak.json file is in a different location you can specify it:
Try adding file to application first, if you fail try the another method mentioned below. Both works perfectly.
var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'); */
/* Else you can declare constructor manually */
var keycloak = Keycloak({
url: 'http://localhost:8080/auth',
realm: 'Internal_Projects',
clientId: 'payments'
});
keycloak.init({ onLoad: 'login-required' }).then(function(authenticated) {
alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
alert('failed to initialize');
});
function logout() {
//
keycloak.logout('http://auth-server/auth/realms/Internal_Projects/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri')
//alert("Logged Out");
}
</script>
https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter Reference Link.
Note : Read the comments for 2 methods of adding json credentials.

Javascript request to cross orgin PHP application

I have a PHP application that I want to run through XMLHttpRequests on my front end part, this works fine as it's pratically the same as "normal". This works fine.
I get really confused when I start trying to do secure cross origin requests. For instance, some requests I want to only permit if a user is logged in. But, when testing if a session is still there, it doesn't exist anymore. I just don't want random people tapping into someones profile, for instance. Or gain any sort of data I don't want random people to see.
What I want
Requests through this model shown below, but make them secure. Because some data I want for protect to logged-in users only. How do you do that? I can't wrap my mind around that.
Basically, I now have the issue that I can't check on the PHP end if a user has a active session, as PHP sees it as a totally new thing. Essentially, how do you do it like web broswers do it? It's probably just really stupid, but I can't wrap my mind around it.
What I've tried
I've tried requesting where one sets the $_SESSION, then requesting it where it returns $_SESSION, but it return nothing. This means I can't check if the request comes from a loggedin user.
You can use JSON Web Tokens for communicating securely across devices.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA.
Source
You basically send a token with each request to sources you want to secure behind a login. Then server side you veryfy that token. Upon login you generate that token and include it in your response. In your frontend you can store the token in local storage on the client machine. For example jQuery has this plugin for local storage.
Here is a super basic example of what you need to do in PHP.
Do your login using javascript/jQuery. Send username/password to login.php for example and authenticate the user like you would normally do.
login.php
use \Firebase\JWT\JWT;
$salt = 'some_salt_string';
$algo = 'HS256'; // allowed ones
$params = array(
"iss" => 'http://example.com', // your own identification
"aud" => ['user_id'=>4324], // client identification
"iat" => time(), // start validity
"exp" => time()+(3600*24) // end validity
);
$token = JWT::encode($params, $salt, $algo);
// example data
$data = [
'example_1'=>'value 1',
'example_2'=>'value 2'
];
$response = array_merge($data,['token'=>$token]);
header('Content-Type: application/json');
echo json_encode($response);
auth.php
use \Firebase\JWT\JWT;
/**
* http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
* Get header Authorization
* */
function getAuthorizationHeader(){
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER["Authorization"]);
}
else if (isset($_SERVER['HTTP_AUTHORIZATION'])) { //Nginx or fast CGI
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
// Server-side fix for bug in old Android versions (a nice side-effect of this fix means we don't care about capitalization for Authorization)
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
//print_r($requestHeaders);
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
return $headers;
}
/**
* http://stackoverflow.com/questions/40582161/how-to-properly-use-bearer-tokens
* get access token from header
* */
function getBearerToken() {
$headers = $this->getAuthorizationHeader();
// HEADER: Get the access token from the header
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return null;
}
$token = getBearerToken();
$salt = 'some_salt_string';
$algo = 'HS256';
$decoded_token = JWT::decode($token, $salt, $algo); // returns object
// you can access the audience properties to verify the user id against a requested resource
$user_id = $decoded_token->aud->user_id;
// finally check user id and either deny or allow access
javascript
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-storage-api/1.9.4/jquery.storageapi.min.js"></script>
<script>
var storage=$.localStorage;
function login() {
$.ajax({
url: 'https://example.com/api/login',
type: 'POST',
data: {
username:'Username',
password:'Password'
},
success: function (data) {
storage.set('auth_token',data.token); // store returned token to local storage using the jQuery plugin"value"
},
error: function () {
alert('Error occured');
},
});
}
function testApi() {
$.ajax({
url: 'https://example.com/api/test',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'bearer '+storage.get('auth_token')); // append the token. Mind the space.
},
data: {
query:'value'
},
success: function () {
},
error: function () {
},
});
}
</script>
Include the auth snippet in your secure pages or better said API endpoints.
CORS or cross origin request are to allow other domains to access your web-services. The feature you are asking is user level access or we can say which is public and which is restricted to user roles. It's not something related to CORS. Secondly session is restricted to one system. Please read this page of w3schools for better understanding of session https://www.w3schools.com/php/php_sessions.asp
You can also maintain an user level variable in your mysql or whatever db you are using on the server side to know what is the user level and then bring it to the correct session and with each request check the session value for the type of user like $_SESSION["user_type"] which you can bring from your db and then destroy the session on logout.

Refresh Office365 Authorization Token from Javascript

I currently have an issue with one of my apps.
The issue is that a user can keep the page open for a prolonged period of time before entering any data, so occasionally, when they enter data and hit the submit button, they are redirected to o365 for authentication and therefore lose the entered data.
I have all the standard authentication working for the app. However, i believe in order to do this, i would need to get a refreshed token in javascript when the submit button is clicked, and send this token to an api method in order to give access.
Is this possible and does anybody know how to go about it?
It is an MVC ASP.NET application using Owin O365 security with Microsoft Azure AD.
I am not sure what information or code snippets would be relevant here so if there is anything i can provide, please ask.
I have found multiple examples of getting tokens etc with angular, however, this is not an SPA and does not use angular.
Many Thanks in advance.
UPDATE
I have attempted to retrieve a token using ADAL JS using the following code but it doesnt seem to recognise the AuthorizationContext(config) call:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/adal.min.js"></script>
$('#btnSubmit').on('click', function (e) {
e.preventDefault();
CheckUserAuthorised();
});
function CheckUserAuthorised() {
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '##################',
clientId: '###################',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
var authContext = new AuthorizationContext(config); //THIS LINE FAILS
var user = authContext.getCachedUser();
if (!user) {
alert("User Not Authorised");
authContext.login();
}
else {
alert('User Authorized');
}
}
This gives the following error in console:
'AuthorizationContext' is undefined
UPDATE
I have no got passed the undefined error. This was because i was calling AuthorizationContext rather than AuthenticationContext. Schoolboy error. However now, whenever i check the user property of the context, it is always null. And i do not know a way around this as the context is initialised on page load.
There is a lack of a step in your code, here is a simple code sample, hope it will help you:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.10/js/adal.min.js"></script>
<body>
login
access token
get user
</body>
<script type="text/javascript">
var configOptions = {
tenant: "<tenant_id>", // Optional by default, it sends common
clientId: "<client_id>",
postLogoutRedirectUri: window.location.origin,
}
window.authContext = new AuthenticationContext(configOptions);
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
function getToken(){
authContext.acquireToken("https://graph.microsoft.com",function(error, token){
console.log(error);
console.log(token);
})
}
function login(){
authContext.login();
}
function getUser(){
var user = authContext.getCachedUser();
console.log(user);
}
</script>
The code sample is from the answer of No 'Access-Control-Allow-Origin' header with Microsoft Online Auth. The issues are different but they are in the same scenario.
any further concern, please feel free to let me know.
I found a similar example on the web and your problem seems to be related to the object you are instantiating.
Instead of
new AuthorizationContext(window.config);
try
new AuthenticationContext(window.config);
The code ran just fine showing that the user was not authenticated.

Keep getting a "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup" when attempting to google plus login on my web app

I'm trying to implement Google plus sign up on my web app and I followed the google docs to set up the sign up however when I attempt a signup after accepting permissions and using the access token returned to me any api restcall I make returns the Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup error. I have already signed up my app with a ouath 2.0 key, so I don't seem to get what I'm doing wrong. Here is my code.
Cient Side:
const clientId = "5XXX000XX.apps.googleusercontent.com";
const apiKey = "AIzaSyCAXE5JSa36jcC*X7HV40SBcIWBiVGUTBE";
const scopes = "https://www.googleapis.com/auth/plus.login";
let accessToken = null;
function initer() {
gapi.client.setApiKey(apiKey);
// alert("Hello init");
if ($("#authorize-button").length > 0) {
$("#authorize-button").click(onLoginClick);
}
}
function onLoginClick() {
// $("#modalLoading").modal();
// alert("yeah");
gapi.auth.authorize({ client_id: clientId, scope: scopes, immediate: false }, onConnect);
}
function onConnect(authResult) {
// alert("On connect");
if (authResult && !authResult.error) {
alert("Hey");
accessToken = authResult.access_token;
triggerLogin();
} else {
alert("Error");
}
}
triggerLogin = function() {
alert("Triggering login");
$("#modalLoading").modal();
$.ajax({
url: window.config.site_root + "account/google_login",
type: "POST",
data: "access_token=" + accessToken,
success: onLogin,
error() {
onError("Logging In", "starting your session");
},
});
};
onLogin = function(login) {
alert("Login start");
$("#modalLoading").modal("hide");
if (login.operation) {
location.reload();
} else {
alert("Register will start");
triggerRegistration();
}
};
triggerRegistration = function() {
$("#modalLoading").modal();
$.ajax({
url: window.config.site_root + "account/google_registration",
type: "POST",
data: "access_token=" + accessToken,
success: onRegistration,
error() {
alert("An Error");
},
});
};
onRegistration = function(data) {
alert("Handling register");
$("#modalLoading").modal("hide");
if (data.account_exists) {
stage.showErrorModal(
"Account already registered",
"There is already an account with that email address, are you sure you created an account using this login method?",
);
} else if (data.operation) {
alert("Login now");
triggerLogin();
} else {
alert("Error");
onError("Registering", "creating your account");
}
};
Here is my server side code
public function google_registration()
{
$access_token = (isset($_POST["access_token"]) && !empty($_POST["access_token"])) ? $_POST["access_token"] : null;
$name = null;
$email = null;
$account_id = null;
$picture = null;
$gender = null;
try
{
if($access_token)
{
$me = file_get_contents("https://www.googleapis.com/plus/v1/people/me?access_token=".$access_token);
if($me)
{
$me = json_decode($me);
$name = $me->name.formatted;
$email = $me->email;
$account_id = $me->id;
$picture = $me->image;
$gender = ($me->gender == "female") ? 1 : 0;
}
}
}
catch(Exception $error)
{
// let the system handle the error quietly.
}
return $this->service_registration("google", $name, $email, $account_id, $picture, $gender);
}
I too ran into the same error - "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup".
I went and checked my google developer console under APIs for the project associated with the API key/ auth key, eg, https://console.developers.google.com/project/<your app id>/apiui/api. The status for Google+API was set to OFF. I turned it ON.
I then got another access token, and then tried with the new one. It worked, ie, the error was gone and I got the profile details. To cross-check if that was indeed the cause of the error, I went back to console and disabled Google+ API. But now, I get the error:
"Access Not Configured. Please use Google Developers Console to activate the API for your project."
So, I am not 100% sure that it was the turning on/off of the Google+ API in my developer console, but do ensure that this is turned on. Also, wait a few minutes after turning on, and ensure that you get a fresh token each time before trying it.
Make sure you have Google+ Api here enabled.
Without it you will get errors like:
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
To enable it:
1) open https://console.developers.google.com
2) choose your project (top right corner)
3) search for "Google+ API" in search box and enable it if it is not enabled already.
This issue happens when you are already logged in and still try to login again and again. I faced same error so did some experiments 1) I opened website on my mobile and everything was fine. 2) Then i tried on another laptop and used different gmail account to login and it again worked fine. 3) On my first laptop i tied again by clicking "Signin" button i got same error, so i opened google.com then logged out completely and then tried again, this time it worked. So i believe, Issue is clicking login button again and again without logout.
I am not sure if this is a really a issue, but atleast this is what i found. I am still trying, trying and trying , will post if i found anything else.
Cheers !!
You have to add the apiKey with the URL:
$curl = curl_init( 'https://www.googleapis.com/urlshortener/v1/url?key=AIza3834-Key' );
So I ran into this issue and the above two methods/solutions (enabling API access, and signing out of accounts) did not work for me because for google+ signin you have to pass in the access token in the authorization header of the http call.
Here's how you do it via jQuery:
$.ajax({
type: "GET",
url: "https://www.googleapis.com/plus/v1/people/me",
headers: {
"Authorization":"Bearer " + {access_token},
}
});
It seems your issue is with the server side code where you pass in access_token in the params (which is not necessary).
Here's my attempt on what the PHP implementation would look like:
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Authorization: Bearer ".$access_token
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('https://www.googleapis.com/plus/v1/people/me', false, $context);'
Hopefully you're sending that access token over https! It might be worth considering using the code instead and doing an exchange on the server side for an access token, for improved security if nothing else, there's some documentation on that approach here: https://developers.google.com/+/web/signin/server-side-flow
With regards to the problem you're seeing, it seems like the access token is bad, or not making it through correctly. Can you check the access token that you receive against the tokeninfo endpoint: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token= - that should show valid information. Nothing stands out as being off in the code, but if the token is getting mangled you might see a similar error.
I got have the same issue, The solution is: set APIKEY
I was also desperate, and finally I managed to find a solution. The only problem is to add the correct api token linked to your app, in my case was the browser token, and it all works.
Example: I wanted to have all the events associated with my calendar
https://www.googleapis.com/calendar/v3/calendars/{calendar_id}/events?&key={api_key}
maybe I will help someone who is having the same problem.
Good Luck
I was trying to use access_token to fetch a returning user's name and picture when they already logged in during a prior session. After running into the "unauthenticated use" error message, this is what finally worked via cURL in PHP.
//initialize provider specific params for oauth2
$access_token = <fetched from app database from last login> //remember to never expose this to users
$api_url = 'https://www.googleapis.com/plus/v1/people/me';
$headers = [
'Authorization: Bearer '.$access_token
];
//send curl request
$curl = curl_init();
$curl_opts = [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POST => 0, //GET
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_URL => $api_url,
CURLOPT_HTTPHEADER => $headers,
];
curl_setopt_array($curl, $curl_opts);
$curl_response = json_decode(curl_exec($curl), true);
$curl_status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
//parse curl response from provider into name and icon fields for my app
$name = $curl_response['displayName'];
$icon = $curl_response['image']['url'];
Note that https://www.googleapis.com/plus/v1/people/me (for returning users via access_token) and https://www.googleapis.com/oauth2/v4/token (for initial login via code) return the user name and picture in different fields/structures.
I had a problem on JavaScript side (Client Side).
In my case it was necessary to add API_KEY to gapi.client.init()
Full my function:
async function initClient () {
return new Promise((resolve, reject) => {
const API_KEY = "YOUR_GOOGLE_API_KEY"
const CLIENT_ID = "YOUR_GOOGLE_OAUTH2_CLIENT_ID"
const DISCOVERY_DOCS = ['https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest']
const SCOPES = 'https://www.googleapis.com/auth/youtube.readonly'
const initData = { apiKey: API_KEY, clientId: CLIENT_ID, discoveryDocs: DISCOVERY_DOCS, scope: SCOPES }
gapi.client.init(initData).then(function () {
// YOUR CODE HERE
}, function (error) {
reject(new Error('Reject Error: ' + error))
})
.catch(err => console.log('Catch Error', err))
})
}
API_KEY and CLIENT_ID can be taken from here (Google Cloud Platform -> APIs & Services -> Credentials -> Credentials [Tab])
In my case, it happened at a specific time of the day, After spending few hours finally found that my daily quota limit (Queries per 100 seconds) was exceeded at that time because of a high number of requests. so it was throwing the error. I have contacted google support to increase them.
In my case, it was because I was using an old access token. You must keep in mind that access tokens have a short life span, so you must use the refresh token to generate a new access token. Example (using a PHP Class):
// Get the access token from DB or filesystem
$accessToken = $this->getAccessToken();
// Set the access token
$this->client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($this->client->isAccessTokenExpired()) {
$this->client->fetchAccessTokenWithRefreshToken($this->client->getRefreshToken());
// Save the new access token to DB or filesystem
$this->saveAccessToken($this->client->getAccessToken());
}
I just had same problem and found out what was wrong.
When you enable your Google Plus API from your Library, there is extra steps to completely activate. You have to click "Manage" button in the Google Plus API Library page and fill up two question answer and submit. That's all!!
This fixed my issue and I hope its fixes yours as well. Here is the screenshot of that page where i was taken after I clicked "Manage" button which says "Add credentials to your project".
I'm getting the following error:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use
requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use
requires signup."
}
}
I'm not sure but i think its caused in my case on the OAuth consent Screen of the Google Developers Console, there is this message,
The user cap limits the number of users that can grant permission to your app when requesting unapproved sensitive or restricted scopes. The user cap applies over the entire lifetime of the project, and it cannot be reset or changed. Verified apps will still display the user cap on this page, but the user cap does not apply if you are requesting only approved sensitive or restricted scopes. If your users are seeing the "unverified app" screen , it is because your OAuth request includes additional scopes that haven't been approved.
I'm requesting restricted scopes:
private val SCOPES: List<String> = arrayListOf(DriveScopes.DRIVE_FILE, DriveScopes.DRIVE_APPDATA, DriveScopes.DRIVE)
Although my app is in development it seems to require verification, I think over the lifetime of the development of my app i have signed in over 100 times. (See OAuth user quotas)
https://support.google.com/cloud/answer/7454865?authuser=0
I Guess i have to verify my App Does anyone know if this is the case...?
I think (at least for some) this error could be leading them in the wrong direction. In my case, my API call was working, then suddenly stopped. Here was my thought process while working through this error, hopefully it will help someone:
OBSERVATIONS
New error was produced
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
This occurred during a test attempting to send an update to the Google Calendar API with the following call:
service.events().patch(calendarId='primary', eventId=id, sendNotifications=True, body=update).execute()
This occurred shortly after I updated the data in my time_start variable referenced in the json that gets sent to google:
update = {
'start': {
'dateTime': time_start, # Specifically this variable (time_start) was changed
'timeZone': time_zone,
},
'end': {
'dateTime': time_end,
'timeZone': time_zone,
},
'description': description,
}
The information in my time_start variable changed from:
2020-05-13T17:06:42-07:00 to 2020-05-13T17:06:42 (note the missing UTC offset)
ACTIONS
Updated my code populating time_start to include the missing UTC offset that was being passed to google calendar API.
RESULTS
The payload successfully transmitted to google calendar and my event was patched with the update
Just in case someone has gotten this issue while using Drive API (in my case, using Python as programming language), this can also occur due to an incorrect metadata update. Here is my error report:
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
This was, in essence, due to the fact that I was trying to alter both copyRequiresWriterPermission and viewersCanCopyContent fields over an application/vnd.google-apps.folder, which is not allowed.
No clue about why Google chose to send an error report so unrelated to the actual error.
This is because the scope you use for Drive API is labelled restricted.
You can make a limited number of requests to get file data/content.
Once you have reached the limit you have to get another access_token for the existing session. It is like having refresh_token.
You can wrap your code that sends requests to get files in try...catch
If that error is thrown you can requestAccessToken.
NOTE: For refreshing the access token in an existing session, you do not need to ask for content again.

Categories

Resources