I've followed the guide on how to use GCS on their site:
but
Once Unauthorized used
I then get
Failed to load resource: the server responded with a status of 400 ()
{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad
Request"}],"code":400,"message":"Bad Request"}}
Here is my step
create the javascript page from this
authSample.html
change clientId to google console page
OAuth 2.0 user ID:??????????????????????.apps.googleusercontent.com
change apiKey to google console page
OAuth 2.0 user api key
run the authSample.html
What am I doing wrong?
So this bug occurs because of an incorrect way of loading and authorising API's.
The correct way is to first use
gapi to load client (no auth required)
next load, the "storage","v1"
finally Authorise
gapi.load('client', () => {
gapi.client.load('storage', 'v1', authResult =>{
gapi.auth.authorize({
client_id: CLIENT_ID,
scope: SCOPES,
immediate: false
},authResult=>{
if (authResult && !authResult.error) {
var request = gapi.client.storage.buckets.list({
'project': PROJECT_ID
});
request.execute(function(resp) {
console.log(resp)
});
} else {
alert("Un-Authorised")
}
});
});
});
The supported client libraries are limited to a number of languages only. If you wish to build a solution around those, you can refer these here
https://cloud.google.com/storage/docs/json_api/v1/libraries#api-client-libraries
Related
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.
I'm developing an application with Cordova and would like to save files in Googe Drive.
I've got success in login to Google, using the cordova-plugin-googleplus (https://github.com/EddyVerbruggen/cordova-plugin-googleplus). However I could not get the plugin returns to me accessToken or idToken so I could use with Google javascript API.
window.plugins.googleplus.login(
{
'scopes': 'https://www.googleapis.com/auth/drive.file profile',
'offline': true,
'webApiKey': ‘CODE’
},
function (obj) {
$scope.$apply(function() {
$scope.srcImage = obj.imageUrl;
$scope.NomeGoogle = obj.displayName;
});
},
function (msg) {
alert('Erro');
alert('error: ' + msg);
}
);
I tried using the code below, but returned me the following error:
"Uncaught gapi.auth2.ExternallyVisibleError: Invalid cookiePolicy"
gapi.load('auth2', function() {
gapi.auth2.init({
client_id: 'REVERSED_CLIENTID',
}).then(function(){
auth2 = gapi.auth2.getAuthInstance();
console.log(auth2.isSignedIn.get()); //now this always returns correctly
});
});
I managed to figure out the problem, why wasn´t getting the serverAuthCode from plugin.
It is necessary to create 2 credentials on the Google Developers Console. The 1st must be Android, this will be for the plugin and the 2nd should be a Web App, this is necessary to achieve serverAuthCode.
The code looks like this
window.plugins.googleplus.login(
{
'scopes': 'https://www.googleapis.com/auth/drive.file profile',
'offline': true,
'webApiKey': ‘REVERSED_CODE of Web App Credential’
},
function (obj) {
$scope.$apply(function() {
$scope.srcImage = obj.imageUrl;
$scope.NomeGoogle = obj.displayName;
});
var data = $.param({
client_id: 'REVERSED_CODE of Web App Credential',
client_secret: 'SECRET_CODE of Web App Credential',
grant_type: 'authorization_code',
code: obj.serverAuthCode
});
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
}
}
$http.post("https://www.googleapis.com/oauth2/v3/token", data, config).success(function(data, status) {
//data.access_token;
/** from now you can do use of google API **/
})
.error(function(data, status) {
console.log(data);
console.log(status);
});
},
function (msg) {
alert('Erro');
alert('error: ' + msg);
}
);
Thank you for your reply rojobo
At first I was hoping to skip the need for cordova-plugin-googleplus and just use the gapi within Cordova/PhoneGap to handle authentication with Google, but it appears the gapi client authentication may not work within cordova's file:// protocol.
The answer from #Joao sent me in the right direction, but I kept getting the Invalid cookiePolicy error when trying to use the gapi after retrieving the access_token (this was because I was ignoring step #2 listed below, and after authenticating with the plugini I was mistakenly trying to authenticate again with the gapi).
There is a step (#3 mentioned below) that was unclear to me. To authenticate with Google and then use the gapi in Cordova/PhoneGap, this worked instead...
use the cordova-plugin-googleplus to take care of the authentication and access token retrieval, do not use the gapi at all here
load the gapi client library (skip over the gapi.client.init() call and all the normal gapi authentication procedures)
Attach the access token we got from the plugin to the gapi client, and then make your gapi calls as needed
Step #3 took some digging for me to find, and meant I needed to add the access_token
gapi.client.setToken({access_token:'abc123456xyz'});
Once the access token was attached to the gapi client, I could use the gapi within Cordova/Phonegap:
// Load the YouTube API.
gapi.client.load('youtube', 'v3', function() {
// Do stuff...
};
try
window.plugins.googleplus.login(
{
'scopes': 'https://www.googleapis.com/auth/drive.file profile',
'offline': true,
'cookiepolicy': 'none',
'webApiKey': ‘CODE’
}
Until recently I was using the javascript Blogger API v3 to fetch posts from a blog to build an automated index, using the gapi.client.blogger.posts.list() method.
However, it suddenly stopped working. The response now simply includes an error object with the message "We're sorry, but the requested resource could not be found.", as if the blog I'm trying to fetch info does not exist at all. I'm pretty sure my blog ID did not change during my sleep.
So I started digging around, and I found that the OAuth authentication token returned says I'm not actually logged in Google. In the status object from the token, the signed_in property is true but the google_logged_in one is false. Yet the Google login page showed up correctly upon execution and I allowed it, and the token does not have an error property. Why does it says I'm not logged in?
I'm under the assumption that Google blocked my application from making new requests due repeated use (even thought I never reached a dent of the daily quota) and now since the OAuth 2 ID authentication does not work, the API tries to use only the web browser API key, which does not work either since it's a private blog and user permission is required. But I really don't know.
I could not find a similar situation on the internet. I tried deleting both my API and OAuth keys and making new ones, deleting the project from the Google Console Developers and creating a new one under a different account, removing the application from the "allowed apps" in my account and adding it again, not using the browser API key. No game.
I would appreciate any inputs in solving this issue. And before anyone suggests: the "conventional" way of creating an automated index using the blog's feed does not work in my case, since the blog is private and has no feed.
Bellow is the returned access token (redacted a bit):
{
_aa: "1"
access_token: "[Redacted]"
client_id: "[Redacted]"
cookie_policy: undefined
expires_at: "1460999668"
expires_in: "3600"
g_user_cookie_policy: undefined
issued_at: "1460996068"
response_type: "token"
scope: "https://www.googleapis.com/auth/blogger.readonly"
state: ""
status: {
google_logged_in: false
method: "AUTO"
signed_in: true
}
token_type: "Bearer"
}
And bellow an example code of my application:
var apiKey = "myWebBrowserApiKey";
var clientId = "myOAuth2ClientID";
var blogId = "myBlogID";
var bloggerReadOnly = "https://www.googleapis.com/auth/blogger.readonly";
var fetchParam = {
blogId: blogId,
fetchBodies: false,
fetchImages: false,
maxResults: 500,
status: "live",
view: "READER"
};
var authParamIm = {
client_id: clientId,
scope: bloggerReadOnly,
immediate: true
};
var authParam = {
client_id: clientId,
scope: bloggerReadOnly,
immediate: false
};
//Executed as soon the client:blogger.js loads
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
//Check if the user is already authenticated for immediate access
function checkAuth() {
gapi.auth.authorize( authParamIm, handleAuthResult );
}
function handleAuthResult(authResult) {
//If the user does already have authorization, proceed with the API call
if (authResult && !authResult.error) {
makeApiCall();
}
//If he does not, shows the authorization button
else {
authorizeButton.css('visibility', 'visible');
authorizeButton.click(handleAuthClick);
}
}
//The authorization button calls this function, that shows a Google login page
function handleAuthClick(event) {
gapi.auth.authorize( authParam, handleAuthResult );
return false;
}
//Loads the Blogger API, version 3, and runs the fetchPosts() function with a callback
function makeApiCall(){
gapi.client.load('blogger', 'v3', fetchPosts);
}
function fetchPosts(){
//Creates a request to get a list of posts from the blog, using the fetch parameters
var request = gapi.client.blogger.posts.list(fetchParam);
//Execute the request and treats the response with a callback function
request.execute(function(response){
//Do Stuff
}
}
I am trying to get calendar info from google in javascript. I ve read 'how to' manuals. They didn't help. Even this 'helpful' copypasted code (to authorize) didn't. Would somebody be so kind to teach me how to use google api? Maybe someone has some samples to share
And this beautiful js code :
<html>
<button id="authorize-button" onclick='handleAuthClick()'>Authorize</button>
<script type="text/javascript">
var clientId = '***';
var apiKey = '***';
var scopes = 'https://www.googleapis.com/auth/plus.me';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
// Step 3: get authorization to use private data
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
// Step 4: Load the Google+ API
gapi.client.load('plus', 'v1', function() {
// Step 5: Assemble the API request
var request = gapi.client.plus.people.get({
'userId': 'me'
});
// Step 6: Execute the API request
request.execute(function(resp) {
var heading = document.createElement('h4');
var image = document.createElement('img');
image.src = resp.image.url;
heading.appendChild(image);
heading.appendChild(document.createTextNode(resp.displayName));
document.getElementById('content').appendChild(heading);
});
});
}
</script>
Error Message (from Console):
'Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('file://') does not match the recipient window's origin ('null').'
so im stuck on 'gapi.auth.authorize'. nothing works after
Based on the error you're receiving, my guess is that you either do not have your Javascript Origin configured properly on the Google API console you got your Client ID from, and/or you are trying to run your script from the file system instead of through a web server, even one running on localhost. The Google API client, near as I've been able to tell, does not accept authorization requests from the file system or any domain that has not been configured to request authorization under the supplied Client ID.
Google API Console reference :
In Client ID for web application:
Javascript Origins : http://localhost:3000/
Key for browser applications:
Referers : http://localhost:3000/
localhost would work 100%
i got the same error and as you preferred, after running html file in my local web server problem solved.
i created credentials for web application and set following values both to my local with "http://localhost:5000" string
"Authorized JavaScript origins"
"Authorized redirect URIs
i checked the json file too. i got the following json file as a result.
{"web":
{
"client_id":"myClientID",
"project_id":"my-project",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_secret":"XqXmgQGrst4xkZ2pgJh3Omxg",
"redirect_uris":["http://localhost:5000"],
"javascript_origins":["http://localhost:5000"]
}
}
https://developers.google.com/drive/v2/web/auth/web-client
Some APIs will work fine when queried from local files, but some won't.
In response to an error such as yours, try to serve your files from a web server. If you need a quick web server running, use Python's builtin HTTP server (Mac OSX and Linux systems have Python pre-installed). This HTTP server can turn any directory in your system into your web server directory. cd into your project directory and run the following command:
python -m SimpleHTTPServer 3000 The number at the end is the port number your http server will start in and you can change that port number. In our example, your directory would be served from: http://localhost:3000.
I am trying to use the Google plus API (via googie-api-javascript) implementation like so (omitting full code):
var clientId = '7454475891XxxxxxXom4c6n.apps.googleusercontent.com'; //fake client
var apiKey = '-uTH_p6NokbrXXXXXXXXXXXXX'; //Fake Key
var scopes = 'https://www.googleapis.com/auth/plus.me';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
makeApiCall();
} else {
//handle user-approval
}
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
gapi.client.load('plus', 'v1', function() {
var o = gapi.client.plus;
alert(o);
});
}
The code works well upto the point of gapi.client.load (including the user allowing access) - this callback gets called but alert(o) will return undefined.
Upon inspecting the HTTP request I see the .load issues a request to:
https://content.googleapis.com/discovery/v1/apis/plus/v1/rpc?fields=methods%2F*%2Fid&pp=0&key=-uTH_p6NokbrXXXXXXXX
This returns HTTP 400 with the following message:
{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}
My question is - what do I need to change to make this work?
Is there some secret setting I need to enable ? Google+ is enabled in the google-developer-console under the APIs list.
Thanks for the help,
Alon
Problem:
.load issues a request to the google discovery service to load the .JS. The service will error out if the request it receives contains an api-key. (I don't know why the library works like this, it seems like a bug?)
Fix:
gapi.client.setApiKey(""); //NEW
gapi.client.load('plus', 'v1', function()
//re-add the key later if you need it
From Discovery Service docs:
requests you make to the Discovery Service API should not include an API key. If you do provide a key, the requests will fail.
Weird... :P
A little update & more of an explanation. The current Discovery Service page is a little more specific now. They indicate that if the app has an Oauth2 token, then the API Key value is not required. However, I also found that if I have an authenticated user and thus an Oauth2 token (access_token) present, the Discovery Service fails with the error noted in the OP. This seems to contradict the documentation.
You can see the token in the developer tools console with:
console.log(gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse());
Embed that somewhere in a <script>...</script>in your HTML or in a .js file that is called otherwise. Must be after gapi.load(...). It'll stop the script if executed before gapi.load(...) is called.
To get a current user this has to be after the user is authenticated, of course. It does return an object if a user has not been authenticated however. If you are in Chrome, you can expand The Object in the developer tools console window to get a nice outline format of all the stuff in the auth response.
Note that currentUser is undefined prior to a successful authentication. Since this 'fails silently' you should use a conditional statement to verify either the sign in status or that a current user exists in your real code.
For completeness the object instantiation process in my app goes like this, at a high level:
1.) gapi.load(...) - After this gapi.client, gapi.auth2 and other objects are available.
2.) gapi.client.setApiKey("") would be called to 'clear' the api key if it had been set previously for some other purpose.
3.) gapi.auth2.init(...) - After this the auth instance is available via gapi.auth2.getAuthInstance .
4.) Then the login is kicked off using the .signIn() method of the auth instance. The auth instance would be instantiated with something like auth_instance = gapi.auth2.getAuthInstance(); If that's how you do it then the sign in would be auth_instance.signIn().
(...) - means there are several parameters needed.
I also found the Google tictactoe example useful as an example and a simple base for further work.
I hope this is helpful to someone!
you need to call the method
function handleAuthClick(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false} handleAuthResult);
return false;
}
function makeApiCall() {
gapi.client.load('plus', 'v1', function () {
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function (resp) {
'method ajax with you application'
});
});
}
you can see what this do here