Using GIS (Google Identity Services) and API Subpackage (picker) without client package - javascript

I am currently replacing the gapi.oauth2 package, by using the TokenClient according to the guide and everything works fine.
global.google.accounts.oauth2
.initTokenClient({
client_id: CONFIG.google.clientId,
scope: 'https://www.googleapis.com/auth/drive.readonly',
ux_mode: 'popup',
callback(tokenResponse) {
if (tokenResponse && !tokenResponse.error) {
onSuccess(tokenResponse.access_token);
return;
}
onError(tokenResponse.error || 'google authentication failed');
},
})
.requestAccessToken({});
The only issue is that we are not using the gapi.client and would prefer avoiding loading that package as we are only using the token to show a picker by using google.picker.PickerBuilder.
Now after the initialization the GSI package tries to use gapi.client.setToken() which obviously fails as the package is not loaded.
[GSI_LOGGER-TOKEN_CLIENT]: Set token failed. Gapi.client.setToken undefined.
So now i could not find anything in the reference on how to prevent that call to happen, nor how to at least suppress the warning by not e.g hacking in a noop as a placeholder.
Does anyone know if there is any official way to deal with that ?

In my tests the access token is successfully returned to the callback handler.
It looks to be an incorrectly generated warning, annoying yes, but functionally you're okay. A later, official release should remove the warning with no action on your part required.

The new API of GIS (Google Identity Services) maybe remove the setToken of the gapi.
I had to fix it by the code.
gapi = {client: {setToken: function(){ return; }}};

Related

Error: AADSTS500011: The resource principal named "URL" was not found in the tenant

I am trying to add an app to our SharePoint Online site using the template from https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part and we get the error below when we deploy to SharePoint and add the app/Web part to a test SharePoint site. We are using TypeScript as the template uses.
Has anyone else encountered this issue or know where to look for the issue?
Found [object Object]Driver Display External Error: Error: AADSTS500011: The resource principal named https://driverdisplayexternal.azurewebsites.net was not found in the tenant named 7018324c-9efd-4880-809d-b2e6bb1606b6. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant. Trace ID: 358b22eb-cd2c-4091-b592-5a57cbc21d00 Correlation ID: ec96d656-1a36-42e2-a2b9-3ff78efc1e2e Timestamp: 2019-10-01 16:26:06Z
We have added a call to our own client as shown below. We are not sure why the resource principal was not found. The Tenant ID's match and things seem to be set up properly for authentication.
HelloWorldWebPart.ts
...
this.context.aadHttpClientFactory
.getClient('https://driverdisplayexternal.azurewebsites.net')
.then((client: AadHttpClient): void => {
client
.get('https://driverdisplayexternal.azurewebsites.net/api/values', AadHttpClient.configurations.v1)
.then((response: HttpClientResponse): Promise < Order[] > => {
this.domElement.innerHTML += 'Received a response from Driver Display External: ' + response;
return response.json();
})
.catch(error => {
this.domElement.innerHTML += 'Driver Display External Error: ' + error;
console.error(error);
});
});
...
package-solution.json
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "helloworld-webpart-client-side-solution",
"id": "**ID**",
"version": "4.1.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false,
"webApiPermissionRequests": [
{
"resource": "DriverDisplayExternal",
"scope": "User.Read.All"
}
]
},
"paths": {
"zippedPackage": "solution/helloworld-webpart.sppkg"
}
}
Any help or direction to where the issue may be would be very appreciated. Thanks in advance!
Never used this API, but if I had to guess you need to change the value here:
.getClient('https://driverdisplayexternal.azurewebsites.net')
You can use either the client id / application id, or the application ID URI.
Sometimes this problem can occurr when you set a wrong name for the scope you are requesting access for or another configuration parameter.
I suggest to check carefully the scopes name, or maybe directly use the "copy" button from the Azure portal.
In my case it was a simple typo on a scope name.
Not sure if you figured the answer or not. When you used SPFx to request your own custom web api end point. there are couple steps:
request the permission so that you can go to SPO admin to approve the permission you request. for this case, the webApiPermissionRequests->resources needs to your AAD Application's Service Principal DisplayName. once you had AAD App create, you can run Get-AzureADServicePrincipal to get all your ServicePrincipal.
once you request the permission, from your code, you need to call AadHttpClient.getClient() to get aadHttpClient object based on the api resourceEndpoint you want, for this case, you need to pass your web api's Application ID URI which can be found from your AAD App's manifest->"identifierUris". General speaking, this should be something like api://[clientid] format. but you can change it to any unique value.
I hope it helps.
In my case i had to use the App Id when i was consuming a multi tenant API.
In my case, TenantId and ClientId were both ok.
They can be found in AAD. TenantId is right there on landing page:
and then on the same page click Applications then tab All Applications find your application there should be ClientId check if they match.
If that is still not enough, click on the application and find roles
For me, it was roles that were missing after adding those wheels started rolling again:

RingCentral JavaScript SDK Handle Redirect URI points to local JavaScript Function

RingCentral JavaScript SDK handle redirect URI point to local JavaScript function
As-per Doc, they give option
RingCentral.SDK.handleLoginRedirect()
but dont know how to use that
var SDK = require('ringcentral');
rcsdk = new SDK({
server: SDK.server.sandbox,
appKey: '_app_key',
appSecret: 'app_password',
redirectUri: ''
})
function handleredirectURI(){
//handle redirections
}
We need points out our handleredirectURI function
Thanks in advance
Per the documentation. The context is 3-legged oAuth. Here is a demo: https://github.com/ringcentral/ringcentral-demos-oauth/tree/master/javascript
However the demo doesn't use the handleredirectURI method. Which means that the method is simply an utility method and it's not required to use it.
For the usage of handleredirectURI, I will come back and update my answer later.
Update
Here is the source code for handleredirectURI: https://github.com/ringcentral/ringcentral-js/blob/669b7d06254d3620c5a5f24c94b401aa862be948/src/SDK.js#L115-L124
You can see that the method parses win.location to get some useful data and postMessage back to its opener.
Unit tests for handleredirectURI: https://github.com/ringcentral/ringcentral-js/blob/669b7d06254d3620c5a5f24c94b401aa862be948/src/SDK-spec.js#L27-L63
Update 2
I read handleredirectURI' source code, unit tests, sample code again and I think its usage is just like what is written in its documentation:
Popup Setup
This setup is good when your app is rendered as a widget on a third-party sites.
If you would like to simply open RingCentral login pages in a popup, you may use the following short-hand in your app's login page:
var platform = rcsdk.platform();
var loginUrl = platform.loginUrl({implicit: true}); // implicit parameter is optional, default false
platform
.loginWindow({url: loginUrl}) // this method also allows to supply more options to control window position
.then(function (loginOptions){
return platform.login(loginOptions);
})
.then(...)
.catch(...);
In this case your landing page (the one to which Redirect URI points) need to call the following code:
RingCentral.SDK.handleLoginRedirect();
Explained:
Run the first code snippet to open the login popup.
In the redirected to page, run the second code snippet (that one line of code) to get everything else done.
After that the authorization part is done and you can invoke other APIs.
Let me know if you have more questions.

Progressive Web App "does not work offline" error

I have written a progressive web app, following all available guides and examples, but for some reason when I click the Add to homescreen button, I keep getting this mysterious error:
Site cannot be installed: does not work offline
The major difference between my PWA and the examples, is that mine is running purely in a non-root path of the domain, so I have had to add extra paths to the configs in various places so the app is restricted to the non-root folder.
The Google Lighthouse site doesn't help much either, giving a very similar message.
Can anyone suggest what this error might be caused by?
Update:
Looks like Google also picked up on the quick hack and the warning has returned.
So since of Chrome93 (AUG-2021) the quick hack, will not work anymore :
self.addEventListener('fetch', function(event) {})
Solution working "for now" (since we never know what requirements Google will add later on)
I've found a nice article which provides with a few solutions, the first one the author provides is Network-Falling-Back-To-Cache strategy:
your service worker will first try to retrieve the resource from your
server. Then when it can’t do that — because for example, you’re
offline — retrieve it from the cache (if it exists there).
self.addEventListener('fetch', function(event) {
event.respondWith(async function() {
try{
var res = await fetch(event.request);
var cache = await caches.open('cache');
cache.put(event.request.url, res.clone());
return res;
}
catch(error){
return caches.match(event.request);
}
}());
});
You can find all the information and alternative solutions in the article:
https://javascript.plainenglish.io/your-pwa-is-going-to-break-in-august-2021-34982f329f40
I hope this will help futur visitors.
Original answer:
Also you need to define fetch listener in a service worker file:
this.addEventListener('fetch', function (event) {
// it can be empty if you just want to get rid of that error
});
So it took me a couple of hours, but I eventually figured out that there is a required scope parameter that you need to specify in the client JavaScript when connecting to the serviceworker, if it's not running on the root (/) path.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js?v2', {
scope: '.' // <--- THIS BIT IS REQUIRED
}).then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
}
You can see the working product here:
App: https://stampy.me/pwgen/
Manifest file: https://stampy.me/pwgen/manifest.json
ServiceWorker file: https://stampy.me/pwgen/sw.js
App script: https://stampy.me/pwgen/script.js (scroll to bottom for PWA code)
I hope my pain can save someone else some time.

Google Sign In for Websites causing "Signature verification failed" with JWT PHP library

Google web sign in has driven me positively crazy...
I'm building a simple web application, and I'm trying to integrate Google's sign in feature into the website (https://developers.google.com/identity/sign-in/web/).
The JavaScript seemed to go fairly well, and the next step was to verify the id_token I was receiving with my backend server (again, against Google's recommendation: https://developers.google.com/identity/sign-in/web/backend-auth).
It's a PHP-based web application, and I've successfully installed the Google Client API library using composer: composer require google/apiclient, but when posting my id_token value to my PHP backend system I'm consistently receiving the following error:
Firebase\JWT\SignatureInvalidException
File: .\vendor\firebase\php-jwt\src\JWT.php:112
Message: Signature verification failed
Stack trace:
#0 .\vendor\google\apiclient\src\Google\AccessToken\Verify.php(103): Firebase\JWT\JWT::decode('eyJhbGciOiJSUzI...', '-----BEGIN PUBL...', Array)
#1 .\vendor\google\apiclient\src\Google\Client.php(712): Google_AccessToken_Verify->verifyIdToken('eyJhbGciOiJSUzI...', '10...')
I've also used the id_token value on Google's "tokeninfo" endpoint (https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123), and the id_token validates perfectly, so I'm sure it's not the id_token value that's wrong. It's also passing it perfectly via the POST variable to the PHP script, so I'm at a bit of a loss.
Here's my code:
Javascript:
<script src="https://apis.google.com/js/platform.js?onload=googleAppStart" async defer></script>
<script>
var googleAppStart = function(){gapi.load('auth2', initGoogleSignIn);};
var auth = false;
function initGoogleSignIn(){
auth = gapi.auth2.init({
client_id : 'client-id-is-here',
scope : 'profile'
});
auth.attachClickHandler(document.getElementById('my-button'));
auth.isSignedIn.listen(googleSignInChanged);
auth.currentUser.listen(googleCurrentUserChanged);
if (auth.isSignedIn.get() == true)
auth.signIn();
}
function googleSignInChanged(signed_in){}
function googleCurrentUserChanged(user){
var auth_response = user.getAuthResponse();
var id_token = auth_response.id_token;
if (id_token != undefined){
var url = '/verify-google-signin';
var params = {id_token: id_token};
jQuery.post(url, params, function(data){}, 'json');
}
}
</script>
...and my PHP catching the POST:
<?php
require_once '/vendor/autoload.php';
$credentials = array("client_id" => "client-id-is-here");
$client = new \Google_Client($credentials);
$data = $_POST;
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
// Exception generated here...
$payload = $client->verifyIdToken($id_token);
}
?>
Thank you so much for taking the time to read this, and for any assistance! It's greatly appreciated!
I had the same issue today.
Easier if you just execute:
composer require firebase/php-jwt:4.0
Fortunately you can verify id_token without google library as described here https://developers.google.com/identity/sign-in/web/backend-auth#calling-the-tokeninfo-endpoint
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
try {
$res = (new \GuzzleHttp\Client())->request('GET',
'https://www.googleapis.com/oauth2/v3/tokeninfo', [
'query' => ['id_token' => $id_token],
]);
$payload = json_decode($res->getBody()->getContents(), true);
//you still need to check that the aud claim contains one of your app's client IDs
if ($payload['aud'] != "client-id-is-here") {
throw new \Exception("App Isn't valid", 422);
}
} catch (RequestException $e) {
//IF token isn't valid you will be here
if ($e->hasResponse()) {
/** #var \GuzzleHttp\Psr7\Response $resp */
$resp = $e->getResponse();
$error = json_decode($resp->getBody()->getContents(), true)['error_description'];
throw new \Exception($error, $resp->getStatusCode());
}
}
}
If you have no exceptions then your token is valid
It is a problem with php-jwt. Latest version is not working with Google Api Client.
Try to use php-jwt version 4.
I put "firebase/php-jwt": "<5.0" in my composer.json file.
Worked as a charm!
This has been fixed in v2.2.1 of google/apiclient so make sure you are running this version or later if anyone else encounters this issue.
Related discussions here and here.
I've got problems with Google Sign-In backend authentication yesterday, using both google/apiclient 2.2.0 and 2.1.3.
tl;dr it was most likely malfunctions on the Google side or some obscure limits I'm unaware of (nothing in the Developer Console about that).
First, the "idToken" Google was giving me client-side was not a valid JWT: openssl_verify() was rejecting it in Firebase\JWT\JWT, throwing a Firebase\JWT\SignatureInvalidException. I followed your advice, installed google/apiclient 2.1.3 and this exception was not being throwed anymore but the resulting payload was null (so the idToken was still invalid).
A few hours later, I had experienced intermittent results with the apiclient 2.3.0: sometimes the token was invalidated by signature verification (and throwing the signature exception) and sometimes the token was cryptographically valid but the returned payload was null. Once in a while, the token was valid (!).
In the end, the backend authenticaton process was succeeding every time.
As I began experiencing these problems, I tried to fix it generating new OAuth2 keys, revert to a previous verions of my codebase (both server-side and client-side) that I knew was working, removed all browser data and tried to get the token on Cordova with the Sign In for Android. Nothing worked. Also no message in the Developer Console, no visible limits, no security e-mail.
If it's not a bug but a feature, the error handling is quite harsh :)
If you are not using Firebase (taken from https://github.com/googleapis/google-api-php-client)
rm -r vendor/google/apiclient-services
Add this to composer.json
"scripts": {
"post-update-cmd": "Google\\Task\\Composer::cleanup"
},
"extra": {
"google/apiclient-services": [
"Drive" ,
"... any other services here ...",
]
}
Finally
composer install
This will resolve the error message with the added benefit of drastically reducing installed packages. As noted, there are at least 200 API services for GAPI

JavaScript OAuth sign in with Twitter

I have to integrate Sign-in-with Twitter in my app as below.
https://dev.twitter.com/docs/auth/sign-twitter
It is browser based app developed in JavaScript
I have been refering google code java script OAuth, but im confused how to use oauth/authenticate and how to get the oauth_token
Can any one please help me out with some samples ?
Problem with this is that anyone who views your page can also now view your consumer key and secret which must be kept private.
Now, someone could write an app that uses your app credentials and do naughty and bad things to the point that twitter and users ban you, and there isnt anything you can do.
Twitter do state that every possible effort must be made to keep these values private to avoid this happening
Unfortunately, there is currently no way to use oAuth in Browser based JavaScript securely.
Check out the Twitter #Anywhere JSDK authComplete and signOut events and callbacks at https://dev.twitter.com/docs/anywhere/welcome#login-signup
twttr.anywhere(function (T) {
T.bind("authComplete", function (e, user) {
// triggered when auth completed successfully
});
T.bind("signOut", function (e) {
// triggered when user logs out
});
});
Use below code in consumer.js and select example provider in index.html drop down list
consumer.example =
{ consumerKey : "your_app_key"
, consumerSecret: "your_app_secret"
, serviceProvider:
{ signatureMethod : "HMAC-SHA1"
, requestTokenURL : "https://twitter.com/oauth/request_token"
, userAuthorizationURL: "https://twitter.com/oauth/authorize"
, accessTokenURL : "https://twitter.com/oauth/access_token"
, echoURL : "http://localhost/oauth-provider/echo"
}
};
Since I was searching for the same thing, trying not to use a custom PHP solution, I came across this very simple integration at http://www.fullondesign.co.uk/coding/2516-how-use-twitter-oauth-1-1-javascriptjquery.htm which uses a PHP proxy that accepts whatever twitter api call you'd like to retrieve from your javascript ..
I'm definitely taking a look at it

Categories