Google app script web app, how to create a login button? - google-apps-script

I have create script backed by a Google Spreadsheet in Google Drive and published it as a web app, setting "Execute the app as: me" and "Who has access to the app: Anyone, even anonymous". The main page serves html content from the spreadsheet.
The basic functionalities are: a "random internet user" is able to see some informations, while an user logged with his Google Account is able to submit information as well.
The issues is - if I set the permission to "anyone" people are first redirected to the standard google login page, and once logged in have to accept the script permissions. Once that's done, navigating to the web app will give the "logged in user" version as long as you are logged in with your google account.
However - if the web app is set to allow "anonymous users" there doesn't seem to be any (at least obvious way) to allow anonymous users to login and accept the app permissions.
What I have tried until now:
a link to the url google redirects me to if I am not logged on if the web app require the user to be logged in. That works, but I feel it is not the right way and also, once logged in, there is no way to logout or to switch account; it seems that once you are logged in, you are logged in forever
to use https://developers.google.com/apps-script/reference/script/authorization-info#getAuthorizationUrl() to get the auth url - but I don't know how to use the url it returns (navigating the user to that page in the web app frame on the top frame both result in a blank page)
How can I get a login (and possibly a switch login) url to allow anonymous users to login in my web app?

Created sample code for 2 .gs web app projects:
one - no auth, runs as owner, anonymous can access
two - needs auth, runs as user, anyone can access
...as I have no idea what your "I got it to work redirecting the user to the URL" statement looks like in code.
The 1st file has a button with a click listener to act as the login button, but it's just calling for a window.top.location.href change.
The 2nd app is using ScriptApp.invalidateAuth(); to log users out after being called from a client-side button click.
Demo - 1st web app url
I'd still vote to just offer a 2nd web app as a link that pops open in a new window though and as I note in the comment, the setup above forces users to re-authorize each time and after the signout.

Related

Authentication issues with apps script Web App

I am in the process of developing a google apps script web app designed for school teachers and students. I have deployed a version of the web app with following settings:
Execute as: User accessing the web app
Who has access: Anyone with Google account
My intention is to make this app available to anyone with a google (gmail, or edu/org google account).
The app still has a Publishing status of 'Testing' in the 'OAuth consent screen' settings. I am trying to get a few users test this web app.
Users in my google domain all seem to be able go through the OAuth2 steps, and access it without issues.
Test users with #gmail.com accounts that I have added to the 'Test users' list in 'OAuth consent screen' settings are able to go through the OAuth2 steps, and access it without issues.
BUT, test users that I have added to the 'Test users' list in 'OAuth consent screen' settings that are google EDU domain accounts (not #gmail.com) can not seem to get past the OAuth2 steps they are presented with. I have two such users, from two different google EDU domains, and both have the same exact issue:
Upon accessing the app URL, they are presented with a google sign in
prompt.
User clicks on "Review Permissions" to open the OAuth flow
in a popup.
User chooses/confirms the google EDU account they wish to
use to sign in.
Everything normal upto the above step, but on the
next screen, they see this message and there is no way to proceed:
Something went wrong
Sorry, something went wrong there. Try again.
The url on the popup at this point starts with https://accounts.google.com/info/unknownerror?access_type=offline&login_hint=xxx
Scopes requested - if relavant:
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/forms",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
My questions:
How do I resolve this issue?
Is this issue specific to just the 'Testing' status, or might this still be an issue with the app when it is published?
Update: It appears that the issue goes away if I publish the app (in OAuth Consent screen settings).

How to allow Google App Maker app access with no sign-in required

I have created an App in Google AppMaker and have shared the Deployment to Anyone with the link can view (No sign-in required).
Application Access in Deployment Settings is set to "Do not restrict access to this application".
Application is set to runs with Developer Account.
However, if someone try to access the app with the..
..Deployment URL (https://script.google.com/macros/.../exec), they get redirected to login screen (https://accounts.google.com/signin/...),
the app does open correctly after signing in, but the sign-in shouldn't be required.
..Link to share (https://drive.google.com/file/.../view), they get: No preview available
I switched once to "Application set to runs with User Account", but results remains same. Actually, I reset this setting as I consider "Application set to runs with User Account" to require User authentication in order to load their assigned permission.
I most probably missed something on the way of sharing my app.
Can someone please help?
Let me know if you require more details about this case.
Thanks!!
You can't.
Note: App Maker apps are only available to users in your G Suite domain. You can't share them with external users.
To make sure only users on your domain can access it, users need to sign-in.

Signing into custom web app with G-Suite account

90% of my Google Apps Script/HTMLService web app is available to anonymous users, however user must be signed in with G-Suite account in order to access the remaining 10%.
Desired behavior is that if user is already logged in to G-Suite (e.g. read Gmail from that browser), the web app recognizes the user without prompting to log in again – as if you went to Google Calendar just after reading Gmail. If user isn’t logged in yet – he needs to be prompted to log in using #my_g-suite.com account when accessing the restricted features.
My first try was two app approach: one published as “available to anyone including anonymous” and another “available to members of the my_g-suite.com”. The problem with this approach is that 2nd app only shows log in screen if browser has no google identity. If user is logged in to regular, non-g-suite gmail, strange google Driver error is shown instead of login prompt. I posted question about this a while ago, no solution.
So instead I implemented a sign-in button using this guide. Behavior I’m seeing is not what I expected:
If user is already signed in with UserOne#my_g-suite.com prior to accessing the app (e.g. looked at G-Suite email account), Session.getActiveUser() on server side returns correct user ID, however googleUser.getBasicProfile().getEmail() on client has nothing.
If user has not signed in with G-Suite ID using prior to accessing the app and then signs in using the Sign In button on web app, googleUser.getBasicProfile().getEmail() returns correct user ID, however ), Session.getActiveUser() on server side returns nothing.
If user has signs in using the button as UserTwo#my_g-suite.com, no other G-Suite app recognizes it. So if user then signs in to UserOne#my_g-suite.com and comes back to the app, Session.getActiveUser() says it’s UserOne#my_g-suite.com and googleUser.getBasicProfile().getEmail() says it’s UserTwo#my_g-suite.com. Two conflicting identities simultaneously.
How do I make sign-in into my app be 1) seamless with other G-Suite services rather than having completely separate, app-only 2nd identity and 2) restricted to #my_g-suite.com?
Following #TheMaster advice I tried this:
Created a Google Sites site "login.my_g-suite.com" which is only available to g-suite users and has a single page which says "you are logged in to g-suite"
In my web app which runs as "me" and is "available to everyone, even anonymous", I implemented a check if Session.getActiveUser() is g-suite user. If not, I do window.open("https://login.my_g-suite.com") which opens log-in screen in the new tab as expected.
After user logs in, I reload web app. And here's the sad part:
If browser hasn't been used for non-G-Suite account (like regular Gmail) - all works great. Session.getActiveUser() shows newly logged in user ID
BUT if that browser has been logged in to non-G-Suite account, Session.getActiveUser() has no idea about the fact that I just logged in G-Suite in another tab (even after reloading web app). Which is back to square one.
Comparing this to Google's own apps, this behavior is not much different: e.g. if you read regular non-g-suite gmail, then go and log in to Google drive using G-Suite account, and then reload gmail - it doesn't take you to G-Suite Gmail automatically just because you logged in to G-Suite account on that browser. You need to explicitly tell Gmail that you want to use G-Suite account by invoking active-account-selection menu (round avatar icon on the right upper corner).
Looks like no matter what approach I take, I hit the same wall: the need to tell stand-alone Google App Script which Google identity is current. And I don't see any way of doing that.
What I stated above is no longer true due to recent change by Google. (2) now results in Error 404 instead of login screen.
Sign-in issues which a few days ago were only affecting stand-alone Google App Script apps now are plaguing entire G-Suite. Our volunteer first-responder organization got G-Suite mainly for the secure intranet site (members.my_g-suite.com) where we share internal protocols and documentation. It's built on new Google Sites and Google Team Drive. Before Wednesday attempt to access members.my_g-suite.com used to take to G-Suite login screen. Now it takes them to "404. That’s an error. The requested URL / was not found on this server. That’s all we know.". The only workaround is to force users to log out of personal Gmail each time before accessing G-Suite, which is not a reasonable request for a volunteer using personal device. We feel like Google pulled the rug from under our feet. The only hope is that this is a temporary change and they'll revert it to how it was in the beginning of the week. We also confirmed that this change is not limited to our G-Suite.
This is because your web-app runs inside a iframe. You can force login by denying access to the web-app manually.
onload, Check Session.getActiveUser().getEmail() server side and see if it matches your domain,
If it does, proceed to load your actual web-app
If not, just provide the information that the user needs to login to your gsuite to access.
You can also
Proceed to open https://admin.google.com (or any url specific to your domain) in a another tab
See whether it's open and use setInterval to check the other window.close property. When closed, reload your web-app.

How can I call a JS function when the user cancels the authorization check in the Google API?

I am using the Google Drive API to import user images. It’s all working fine. But I have one question: what should be done if user does not authorize the app?
By default, Google’ API redirects the page to the redirect location. But I want to do something else. For example, I want to call a function in this particular situation.
Explanation:
Steps for authorization (using OAuth 2):
Click on login button.
Go to Google to enter username and password.
Enter the correct username and password.
Click the accept button to grant permission to the app.
Google redirects to your server app, with or without a token.
But if the user clicks on the “cancel” button, Google redirects to the URI I passed in as the redirect URL without authorizing the app (as expected). However I want to call a javascript function in this situation.
How can I do this?
In step 5, the page you return (or redirect to) can have ondocumentready() code which reads the URL and does whatever you want.
I solved this.
I just needed to look at the redirection url I was getting. It was clearly mentioning that user has denied to authorize my app. I just needed to fetch that using $_REQUEST and it was all done.
Thank you all so much by the way to look into this.

appNotInstalled when the refresh token is missing?

Lately I've been noticing a strange behavior when trying to access Drive specific actions. The use case is as follows:
the user installs the Chrome Store application
the user launches the application, we get a refresh token for the email and the profile scopes
the user wants to export a document into Google Drive
error message 403: appNotInstalled is returned
If the user goes to Google Drive and opens a file from there using our application, they are redirected to a new authorization dialog that asks for the email, profile, drive scopes. After the user grants access, the initial export also works fine. My assumption is that the initial refresh token that we had was no longer valid, even though exchanging it for an access token worked and the refresh tokens don't expire.
Shouldn't we receive a more descriptive error message in this case that would suggest that we simply have to redirect the user to the authentication dialog instead of the Chrome Store listing?
The issue might be that you are using a different client id/secret than the one you registered for the Drive SDK.
A quick test would be to:
revoke all granted tokens for your application on your test account
visit your application from the New Tab Page, it should redirect you to the authorization page: copy the URL you generated (do not approve).
visit your application from Drive, it should redirect you to the authorization page: copy the URL (do not approve).
Make sure the 2 URLs are identical (they should be), especially look for similarities in the scope and client_id query parameters.