JWT verification error: JsonWebTokenError: invalid algorithm - javascript

i am trying to implement a single sign on for my web application. I am using gravitee.io for the access managment and token generation.
I followed the steps in gravitees quickstart tutorial and i am now at the point that i want to verify my id_token.
In order to do that i am using the node-jsonwebtoken library. i am using total.js for my backend (which should not be as important, but i still wanted to mention it).
What i have done so far.
i have my client-id and my client-secret as well as my domain secret in the total.js config file
./configs/myconfig.conf (key/secret is changed)
url : https://sso.my-graviteeInstance.com/am
client-id : myClientId
client-secret : uBAscc-zd3yQWE1AsDfb7PQ7xyz
domain : my_domain
domain-public-key : EEEEEB3NzaC1yc2EAAAADAQABAAABAQCW4NF4R/sxG12WjioEcDIYwB2cX+IqFJXF3umV28UCHZRlMYoIFnvrXfIXObG7R9W7hk6a6wbtQWERTZxJ4LUQnfZrZQzhY/w1u2rZ3GEILtm1Vr1asDfAsdf325dfbuFf/RTyw666dFcCcpIE+yUYp2PFAqh/P20PsoekjvoeieyoUbNFGCgAoeovjyEyojvezxuTidqjaeJvU0gU4usiiDGIMhO3IPaiAud61CVtqYweTr2tX8KabeK9NNOXlTpLryBf3aTU1iXuU90mijwXZlmIzD28fWq+qupWbHcFZmmv3wADVddnxZHnFIN7DHGf5WVpb3eLvsGkIIQpGL/ZeASDFa
i added a model to handle the login workflow for total.js in order to get the jwt tokens from gravitee by REST-call.
So far everything works as expected. a session is created and stores the response in it. the gravitee response is the expected json which looks like this
{
access_token: 'some-long-token',
token_type: 'bearer',
expires_in: 7199,
scope: 'openid',
refresh_token: 'another-long-token',
id_token: 'last-long-token'
}
I split up the tokens in seperate cookies because when i tried to save them as a single cookie, i got an error that told me the cookie exceeds the 4096 length limit.
So far everything works just fine. in the frontend ajax call the success callback will be executed, just setting the window.location.href='/'; to call the dashboard of my application. I set this route to be accessible only when authorized, so that when my dashboard is called, the onAuthorize function is called by totaljs.
F.onAuthorize = function (req, res, flags, callback) {
let cookie = mergeCookies(req.cookie);
// Check the cookie length
if (!cookie || cookie.length < 20) {
console.log(`cookie not defined or length to low`);
return callback(false);
}
if (!cookie) {
console.log(`cookie undefined`);
return callback(false);
}
// Look into the session object whether the user is logged in
let session = ONLINE[cookie.id];
if (session) {
console.log(`there is a session`);
// User is online, so we increase his expiration of session
session.ticks = F.datetime;
jwt.verify(
session.id_token,
Buffer.from(CONFIG('client-secret')).toString('base64'),
function(err, decoded){
if (err) {
console.log(`jwt verify error: ${err}`);
return callback(false);
}
console.log(`decoded token user id: ${decoded.sub}`);
return callback(true, session);
})
}
console.log(`false`);
callback(false);
};
I also tried to just send the CONFIG('client-secret') without buffering. I also tried to send the CONFIG('domain-public-key'). But the error i get is always the same:
jwt verify error: JsonWebTokenError: invalid algorithm
When i copy and paste the id_token into the debugger at jwt.io with algorithm beeing set to RS256 i'll see the following decoded values:
// header
{
"kid": "default",
"alg": "RS256"
}
// payload
{
"sub": "some-generated-id",
"aud": "myClientId",
"updated_at": 1570442007969,
"auth_time": 1570784329896,
"iss": "https://sso.my-graviteeInstance.com/am/my_domain/oidc",
"preferred_username": "myUsername",
"exp": 1570798729,
"given_name": "Peter",
"iat": 1570784329,
"family_name": "Lustig",
"email": "peter.lustig#domain.com"
}
i copied the public key from my domain in to the respective textfield and i also tried to use the client-secret. no matter what i do, the error i am getting here is
Warning: Looks like your JWT signature is not encoded correctly using
base64url (https://www.rfc-editor.org/rfc/rfc4648#section-5). Note that
padding ("=") must be omitted as per
https://www.rfc-editor.org/rfc/rfc7515#section-2
I dont understand why there is an algorithm error when i try to verify the token in my backend and some encoding error at jwt.io debugger.
can somebody explain to me on how to fix the issue? Thanks in advance
Pascal
edit: changed title

Related

How to validate JWT token from Google pub/sub push (No pem found for envelope)

Context
I'm following Google's RTDNs guide on enabling Real-Time Developer Notifications. I've successfully created the topic and subscription and have received the push notifications sent to the API that I have created. I would now like to authenticate and validate these messages. For that, I'm following this guide on Authentication and Authorization. Their developer documentation here and here has a seemingly useful example.
The Issue
After following the resources outlined above, I get the following error:
Error: No pem found for envelope: {"typ":"JWT","alg":"HS256"}
Relevant Code
const authClient = new OAuth2Client();
// ...
app.post('/pubsub/authenticated-push', jsonBodyParser, async (req, res) => {
// Verify that the push request originates from Cloud Pub/Sub.
try {
// Get the Cloud Pub/Sub-generated JWT in the "Authorization" header.
const bearer = req.header('Authorization');
const [, token] = bearer.match(/Bearer (.*)/);
// Verify and decode the JWT.
// Note: For high volume push requests, it would save some network
// overhead if you verify the tokens offline by decoding them using
// Google's Public Cert; caching already seen tokens works best when
// a large volume of messages have prompted a single push server to
// handle them, in which case they would all share the same token for
// a limited time window.
// verifyIdToken is failing here with the `No pem found for envelope` error
const ticket = await authClient.verifyIdToken({
idToken: token,
audience: 'example.com',
});
// ...
} catch (e) {
res.status(400).send('Invalid token');
return;
}
res.status(200).send();
});
The Questions
From this, I'm assuming I need to have some public key.
Where do I get said public key?
Where do I put said public key so that the google client is initialized with it?
How can I generate an example JWT to test my endpoint?
Edits
I was able to find the source of this error in their code here:
if (!Object.prototype.hasOwnProperty.call(certs, envelope.kid)) {
// If this is not present, then there's no reason to attempt verification
throw new Error('No pem found for envelope: ' + JSON.stringify(envelope));
}
However, I've verified that the kid attribute does indeed exist in the decoded object:
{"alg":"RS256","kid":"7d680d8c70d44e947133cbd499ebc1a61c3d5abc","typ":"JWT"}
Turns out the kid was invalid and therefore threw the No pem found for envelope error. Once a valid kid was supplied, the error no longer persisted.

Getstream.io "Not authenticated" with read only token

I am using the django getstream.io client. My backend code looks like the following, it generates a read-only token and stores it in the response with my jwt token that is sent on a successful login. This code is at the bottom of my settings.py file, which contains the STREAM_API_SECRET, and STREAM_API_KEY key settings. These are also in my settings.py and match what is in my getstream.io dashboard.
from stream_django.client import stream_client
def jwt_response_payload_handler(token, user=None, request=None):
user_feed_1 = stream_client.feed('user', str(user.id))
readonly_token = user_feed_1.get_readonly_token()
return {
'token': token,
'stream': str(readonly_token)
}
On the frontend, the token is correctly gotten from the login response, which contains the stream token. It attempts to setup a real time stream, but when it connects i get a "Not authenticated error". I have confirmed, that the token passed to the following client side function, matches the token generated above.
function setupStream (token, id) {
var client = stream.connect(STREAM_API_KEY, null, STREAM_APP_ID)
var user1 = client.feed('user', id, token)
function callback (data) {
console.log(data)
}
function failCallback (data) {
alert('something went wrong, check the console logs')
console.log(data)
}
user1.subscribe(callback).then(() => {}, failCallback)
}
I am not sure what I am doing wrong because as far as I can tell everything is setup correctly. The tokens, and user id's match what is on the front and backend.
I am following what is in the documentation, but its not working:
https://getstream.io/docs/#readonly-tokens
When i tried just the following in console:
user1.get({ limit: 5, offset: 0 })
.then(callback)
.catch(failCallback)
The exact error response body i get from that is:
{
"code": null,
"detail": "url signature missing or invalid",
"duration": "7ms",
"exception": "AuthenticationFailed",
"status_code": 403
}
EDIT:
it seems by changing:
get_readonly_token() to .token, creating a read/write token, the client side code works. Does readonly token not work?
so it turns out, I am decoding the read_only token incorrectly. Changing the backend code to the following solved my issues;
'stream': readonly_token.decode("utf-8")

Reset Loopback Password with Access Token

I'm working on a project that uses Loopback as a framework, and includes users and authentication. I added a password reset route generated and sent in an email, and everything seemed to be working correctly. Recently, I discovered that the password reset does not appear to be working. The process for resetting the password here is:
Call password reset method for user
Send email from reset event, including user ID and access token
From reset link, set $http.defaults.headers.common.authorization to the passed token
Call user.prototype$updateAttributes (generated by lb-ng) to update password attribute based on a form
The expected behavior is that the password would be updated on the password reset form. Instead, I get an authorization error as either a 401 or a 500 (seems to go back and forth). I notice that in the actual headers sent to the API, the authorization token does not match what I'm passing from the route. Trying to set it using LoopBackAUth.setUser doesn't work, and neither doesn't updating the authorization property before actually sending the request.
I definitely spent time testing this when it was first added, and I can't figure out what would have changed to break this. I've been following the example from loopback-faq-user-management, but we have an Angular front-end instead of the server side views in that example.
Edit:
I tried opening up the ACLs completely to see if I could update the password (or any properties) of my user object (which inherits from User, but is its own type). I'm still getting a 401 when trying to do this.
Edit #2:
Here are my ACLs and sample code for how I'm calling this.
ACLs from model definition
...
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "updateAttributes"
}
...
auth.js
...
resetPassword: function(user) {
return MyUser.prototype$updateAttributes(user, user).$promise;
}
...
Figured out what the issue was. In our app's server, we were not using Loopback's token middleware. Adding app.use(loopback.token()); before starting the server causes the access token provided in the reset link to work as expected!
While all of the above answers will prove to be helpful, be aware that Loopback destroys a token during validation when it proved it to be invalid . The token will be gone. So when you're working your way through a solution for the 401's, make sure you're creating a new password reset token each time you try a new iteration of your code.
Otherwise you might find yourself looking at perfectly healthy code to change a password, but with a token that's already deleted in a previous iteration of your code, leading you to the false conclusion that you need to work on your code when you see another 401.
In my particular case the access tokens are stored in a SQL Server database and the token would always be immediately expired due to a timezone problem that was introduced, because I had options.useUTC set to false. That cause all newly tokens to be 7200 seconds in the past which is more than the 900 seconds than the password reset tokens are valid. I failed to notice that those tokens were immediately destroyed and concluded I had still problems with my code as I saw 401's in return. Where in fact the 401 was caused by using a token that was already gone on the server.
#OverlappingElvis put me on the right track. Here's a more complete answer for others running into this. The loopback docs are quite limited in this area.
Make sure that you get both the user id and the token in your email and these get populated in the form.
From the form the following code does the job:
function resetPassword(id, token, password) {
$http.defaults.headers.common.authorization = token;
return User
.prototype$updateAttributes({id:id}, {
password: password
})
.$promise;
}
This was way more complicated than it ought to be. Here is my full solution:
1) I expose new method on server side which does the password updating from token.
Member.updatePasswordFromToken = (accessToken, __, newPassword, cb) => {
const buildError = (code, error) => {
const err = new Error(error);
err.statusCode = 400;
err.code = code;
return err;
};
if (!accessToken) {
cb(buildError('INVALID_TOKEN', 'token is null'));
return;
}
Member.findById(accessToken.userId, function (err, user) {
if (err) {
cb(buildError('INVALID_USER', err));
return;
};
user.updateAttribute('password', newPassword, function (err, user) {
if (err) {
cb(buildError('INVALID_OPERATION', err));
return;
}
// successful,
// notify that everything is OK!
cb(null, null);
});
});
}
and I also define the accessibility:
Member.remoteMethod('updatePasswordFromToken', {
isStatic: true,
accepts: [
{
arg: 'accessToken',
type: 'object',
http: function(ctx) {
return ctx.req.accessToken;
}
},
{arg: 'access_token', type: 'string', required: true, 'http': { source: 'query' }},
{arg: 'newPassword', type: 'string', required: true},
],
http: {path: '/update-password-from-token', verb: 'post'},
returns: {type: 'boolean', arg: 'passwordChanged'}
});
From the client-side, I just call it like this:
this.memberApi.updatePasswordFromToken(token, newPassword);

AWS Cognito - Developer Authenticated Identities in JavaScript(Browser)

I have trouble getting credentials in a browser script.
The authentication server returns cognito_identityId and cognito_token.
Then I set a Cookie:
$.cookie('cognito_identityId')
$.cookie('cognito_token')
I tried to get credentials in 4 ways on the browser, and all Failed:
CognitoIdentityCredentials
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxx'
IdentityId: $.cookie('cognito_identityId'),
Logins: {
'myauth': $.cookie('cognito_token')
}
});
// => Error: Missing required key 'IdentityId' in params
assumeRoleWithWebIdentity
var params = {
RoleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/Cognito_xxxxxxxAuth_Role',
RoleSessionName: 'xxxxxxxxxxx',
WebIdentityToken: $.cookie('cognito_token'),
DurationSeconds: 900,
ProviderId: 'myauth'
};
var sts = new AWS.STS({apiVersion: '2011-06-15'});
sts.assumeRoleWithWebIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
// => AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
PolicyDocument
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:xxxxxxxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
GetCredentialsForIdentity
var params = {
IdentityId: $.cookie('cognito_identityId'),
Logins: {
"myauth": $.cookie('oauth.io_token')
}
};
var cognitoidentity = new AWS.CognitoIdentity({apiVersion: '2014-06-30'});
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log(data); // successful response
}
});
// => InvalidParameterException: Please provide a valid public provider
WebIdentityCredentials
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::xxxxxxxx:role/Cognito_xxxxxxxxxxAuth_Role',
WebIdentityToken: $.cookie('cognito_token')
});
// => Error: There were 2 validation errors:
// * MissingRequiredParameter: Missing required key 'IdentityPoolId' in params
// * MissingRequiredParameter: Missing required key 'IdentityId' in params
Questions:
What am I doing wrong?
What is the correct way to use this?
Thank you.
Thank you for your kindness.
I tyied your advice, but did not change.
Error messages.
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
Error: Missing required key 'IdentityId' in params
at fail (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2163:37)
at validateStructure (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2084:14)
at validateMember (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2110:21)
at validate (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2059:10)
at Request.VALIDATE_PARAMETERS (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:800:32)
at Request.callListeners (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3913:20)
at callNextListener (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3903:12)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:787:9
at finish (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:126:7)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:142:9
There are source code below link.
https://github.com/bisque33/my-custom-dictionary
and server side is a AWS Lambda Function.
var aws = require('aws-sdk');
aws.config.region = 'us-east-1';
var cognitoidentity = new aws.CognitoIdentity();
var identityPoolId = 'us-east-1:0dccff0d-5fd7-4d14-b38f-d27204feaecc';
console.log('Loading function');
exports.handler = function(event, context) {
console.log('token: %s', event.token);
var params = {
IdentityPoolId: identityPoolId,
Logins: {
'oauth.io': event.token
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params,function(err,data){
if(err){
console.log(err);
context.fail('Something went wrong');
}else{
context.succeed(data);
}
});
};
This program is Google-Chrome-Extension.
AWS Lambda Function returns token by getOpenIdTokenForDeveloperIdentity.
app/scripts/popup.js calls Lambda Function and set cookies.
app/scripts/background.js calls AWS.config.credentials.get, and returns error.
Am I using it wrong?
Update for Additional Information
Thank you for the additional information.
Error appears on 104 line on background.js
AWS.config.credentials.get(function(){
and 115 line on background.js
dataset.synchronize(
And, My explaination was not enough. Facebook authentication needs the domain(ex. http :// example.com). However, Google-Chrome-Ext does not have domain. It has a domain 'chrome-extension://xxxxxxxxxxxxxxxxxxxx'. Then, I use https://oauth.io. It proxies any authentication and accepts chrome-extension domain.
Popup.js does Facebook authentication through oauth.io sdk. It gets a facebook token, and gives to getOpenIdTokenForDeveloperIdentity. I think facebook token.substr(0,14) is unique. But, If it is wrong, I use another unique identifier(ex. email-address.)
Sorry, I was wrong. AWS.config.credentials.get gives an Error:
Error: Invalid login token.
And, dataset.synchronize shows this Error:
Error: Missing required key 'IdentityId' in params
The first approach you have, using CognitoIdentityCredentials, is most likely the best approach for you to take. I can't spot exactly what's causing the error for you but lets try a couple things:
When using Developer Authenticated Identities, you do need to specify the IdentityId when initializing CognitoIdentityCredentials. You need to get the IdentityId value from the call to GetOpenIdTokenForDeveloperIdentity. However, you shouldn't need to preserve the IdentityId value in a cookie as CognitoIdentityCredentials will cache the id by default in the browser's local storage.
As for your Logins map: It looks like you're trying to use Developer Authenticated Identities. With the JavaScript SDK, use the key 'cognito-identity.amazonaws.com' and make sure the value is the token returned from your backend's call to getOpenIdTokenForDeveloperIdentity.
If you continue to have problem using the CognitoIdentityCredentials approach, please reply here with some more info such as the exact method/code you're calling when you receive the error message, and the traced output (i.e. with console.log('%o',..)) of the params input just before your call to the CognitoIdentityCredentials constructor.
Update Based on Additional Information Provided
I still need to know exactly which line of code you receive the error on, but based on the information provided I think I can still help...
Based on what I see in background.js, it looks like you're trying to initialize CognitoIdentityCredentials using a Developer Authenticated Identities provider. This is where I'm guessing that you're receiving the error.
However, in Popup.js, it looks like you're trying to authenticate the user with Facebook. If you're authenticating your users with Facebook, you should just pass the facebook access token into your Logins map when using Cognito. Just use graph.facebook.com as the key in the Logins map and the access token from Facebook. More detail on how to do this is in the Facebook Integration topic of the Amazon Cognito developer guide.
Facebook vs Developer Authenticated Identities
We can get Developer Authenticated Identities to work for you, but in this case, it doesn't look like the right solution for you since you're not actually doing any additional authentication on the identity in your Lambda function and the unique user identifier that you're passing into the getOpenIdTokenForDeveloperIdentity operation appears to be the facebook token, which is not good by the way since the token itself will change between user sessions even for the same user. Usually a good unique identifier is an email address or a user id used by an internal system.
Facebook Login & Redirects
Since you're ultimately trying to use Facebook for login and Amazon Cognito has built-in integration for Facebook, the best thing for you to do is get an access token from Facebook and pass in the Facebook token to Cognito's login map directly. I'm not sure if this will work with Auth.io or not (I'm just not familiar with it), but as long as Auth.io gives your JavaScript code a bonefide facebook token and you add the same Facebook App ID to both Auth.io and Amazon Cognito's Console, it should work. However, you mentioned you want to use Auth.io to avoid Facebook doing a redirect to a landing page. I could be mistaken, but I'm pretty sure if you're using Facebook's JavaScript SDK you won't need a redirect page. You should only need the redirect page if you're doing Facebook's Manually Build a Login Flow.

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