I am calling the app script execution API from my web app. I am getting ScriptApp.getOauthToken() and storing it inside sheet. When I open my web app I will get the stored access token and calling the execution API with the help of it.
But the problem is, after some time the token is getting expired and it is saying
authorization is required
when I call execution API.
Is there any way to keep access token alive or refreshing it whenever is needed?
I. You cannot and you should not. At least not natively
There is no native Google Apps Script service method for obtaining and exchanging a refresh token (and you would need one if you want to refresh an expired OAuth 2.0 token) for a bearer token. That said, there is no practical reason in storing the short-lived token obtained via getOauthToken method - if a user authorized your application, you can request a token on the fly each time you need to make a request.
II. If you still want to, use a library
There is an officially endorsed library for Google Apps Script that manages OAuth 2.0 flow for you. When using it, you can obtain a refresh token if you set the offline access to true when issuing the token.
III. If you really want to DIY, you can always make your own flow
It is possible to perform a complete Oauth 2.0 flow (both with and without user interaction) by using only the native tools by building a custom JWT token and exchanging it with Google Identity Platform endpoints. But that means you will have to manage everything:
Build JWT custom token headers and payload, then base64 urlencode them and sign with an appropriate signature and concatenate into a token.
Exchange the custom JWT for a short-lived bearer token, validate it and extract expiration time, then persist the token.
Each time you get the token from storage, check for the expiration time, and reissue the token again using the procedure in point 1 - 2.
Handle token revocation (note that you will not be able to invalidate it from Google's servers, only in your application).
And many more caveats along the way.
Note that the token cannot be "kept alive", it goes against the idea behind the OAuth protocol - the lesser the lifespan of an individual token, the better the security of your application.
Related
In my app, after a user sends a message to someone, another function is triggered to notify the receiver. For that, the sender has to have the receiver's push token (front end). My question is: Is that safe? Is there a better approach?
I'm using Firebase but I couldn't figure out a way to send this notification through Google Cloud Functions...
Yes you can treat it as sensitive information. Tokens could contain information that when a malicious user accessed, it can be used to impersonate your app and send their own messages to users. While there's no reported instance (yet), it would be wise to follow the best security practices.
According to this documentation on Sending Notifications with Expo's Push API
We offer the use of an access token alongside the push token as an additional layer of security.
If you're using the expo-server-sdk-node, upgrade to at least v3.6.0 and pass your accessToken as an option in the constructor. Otherwise, pass in the header 'Authorization': 'Bearer ${accessToken}' with any requests to our push API.
Any requests sent without a valid access token after you enable push security will result in an error with code: UNAUTHORIZED.
You can check this blog on Implementing Push Notifications with Expo and Firebase Cloud Functions on how to push notifications securely.
Is there a simpler way to generate a three legged token only using Node js.
I have used the method in the [1]: https://learnforge.autodesk.io/#/oauth/3legged/nodejs, but I am looking for a simpler method, that just gives me the token.
The standard workflow for a 3-legged OAuth token (not just for Forge but for any OAuth 2.0 provider) is typically:
You redirect the user to Autodesk login form
You wait for a callback from the Autodesk login form (assuming the user logged in successfully), and retrieve a temporary code
You exchange the temporary code for an actual access token (and a refresh token)
This process is explained in the docs as well.
Another option that is perhaps a bit simpler is using the "implicit grant" where the step 3 is basically skipped, and the access token is included directly in the callback. The downside of this approach is that you do not receive the refresh token.
Am trying to access forge api endpoint using 2- legged authentication token, but at certain point of time my token becomes invalid or expired. Is that any option to refresh/ increase token expire time in 2- legged authentication process?
For 2-legged token, once they expire, you have no choice but to request another one. That being said, I think this will be managed for you if you use one of the forge/design-automation sdk.
I am trying to run a script off of my Google Drive through the Javascript Google Drive API. This works fine, but only if I sign into my account on the popup that opens. I wish to sign into the same account every time and so was wondering if there was any way to automate the login of this so as to bypass users having to enter in that login information.
In short, you would have login at least once, everytime after the Google Identity Provider JSON Web Token expires. I am not sure how long this would be with the Goolge Drive API, but typically these tokens may be valid for anywhere from a single request to days long.
Here is the Documentation for the Google API OAuth2
https://developers.google.com/identity/protocols/OAuth2
Refresh the access token, if necessary.
Access tokens have limited lifetimes. If your application needs access
to a Google API beyond the lifetime of a single access token, it can
obtain a refresh token. A refresh token allows your application to
obtain new access tokens.
Note: Save refresh tokens in secure long-term storage and continue to
use them as long as they remain valid. Limits apply to the number of
refresh tokens that are issued per client-user combination, and per
user across all clients, and these limits are different. If your
application requests enough refresh tokens to go over one of the
limits, older refresh tokens stop working.
Google has provided a quickstart guide for implementing a user sign via Google Apis. Google uses the OAuth2 protocol in which you must register with Google as a Client application. Once registered as a Client application, you will be issued a Client ID, which you typically provide to your application in some form of application initialization.
Here is a link to their quickstart guide, which will help you get started:
https://developers.google.com/drive/v3/web/quickstart/js
Note that this is a basic example that does not demonstrate how you may approach persisting a JSON Web Token so that the user does not have to login on every request. I outline a simple approach of managing Authentication in JavaScript and Angular to get you moving in the right direction, but incomplete, direction.
For example, in Angular:
// Configures the required variables before Running an Instance of the App
angular.module("yourModuleName").config(configureApp);
AND
// Executed when the App Instance launches, allowing you to connect to Google APIs when the App starts
angular.module("yourModuleName").run(runApp);
Where configureApp and runApp are JS functions that handle application initialization in the AngularJS Framework. The code in the follow example would retrieve the Apps Google Client ID from their own App's REST API. This is just an example of where you could retrieve these credentials from storage, but most likely is not the most secure example:
var configureApp = function($http,$window) {
// Setup your CLIENT ID from your own REST API (or any other mechanism you may choose)
var httpPromise = $http.get("http://myApp.myDomain.com/config/googleClient");
// Handle the Response from the above GET Request
httpPromise.then(
// Handle Success
function(response) {
// Store the CLIENT ID in local storage for example
$window.localStorage.setItem("GOOGLE_API_CLIENT_ID", response.data.clientId);
// Setup the App Wide variables for Google API
// Client ID and API key from the Developer Console
var CLIENT_ID = response.data.clientId;
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly';
// Do more initialization configuration
};
var runApp = function() {
// Initialize the API
gapi.client.init({
discoveryDocs: DISCOVERY_DOCS,
clientId: CLIENT_ID,
scope: SCOPES
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
Which function to use with Angular would depend on the desired app lifecycle you need to target in an Angularjs app. This approach can be applied in other JS frameworks like React and Backbone.
To highlight another perspective from the documentation, updateSigninStatus would be a great place to capture the JSON Web Token returned by Google's Authorization request at which point you could store this token in the browser's window.localStorage for re-use.
You then could reuse the token whenever the Google API requires authentication. Tokens typically have an expiration. Until the token expires, you would be able to prevent the API from displaying a login modal.
This does mean you would still have to manage the logic behind the Authorization process using this approach, monitoring any response from Google requesting a token refresh or re-authentication.
Auth0 is a great Authentication and Authorization plugin available in many languages for connecting with Google and many other OAuth2 Identity Providers. The Google Drive API uses their own Identity Provider Service to confirm the Identity of your apps users in tandem with your registered app's Client ID.
Here are links that I found when implementing Authorization for a project that required me to implement Authorization using the Google Identity Provider:
https://jwt.io/
https://auth0.com/
Best practices for authentication and authorization in Angular without breaking RESTful principles?
https://thinkster.io/tutorials/angularjs-jwt-auth
You are saying that all users login to the same Google account?
In that case you have 2 options.
1/ write a server application that has a stored refresh token. Create an endpoint that allows an authenticated user to request an access token.
2/ embed a refresh token in your JavaScript, but make sure that only authenticated users can load the JS
I am implementing spring oauth2 for securing my rest api. Basically i am limiting the use of rest api to particular users rather then limiting to every users.
I had implemented the backend and secured my api using spring oauth2.
I am following this steps:
1)Send the GET request with the five parameters.
localhost:8080/SpringRestSecurityOauth/oauth/token?grant_type=password&client_id=Awyi123nasdk89&client_secret=asdj39m32##$s&username=rahul#gmail&password=rahul#9831
2) Server validates the user with the help of spring security and return the json response with access code.
{
"access_token": "22cb0d50-5bb9-463d-8c4a-8ddd680f553f",
"token_type": "bearer",
"refresh_token": "7ac7940a-d29d-4a4c-9a47-25a2167c8c49",
"expires_in": 119
}
3)I access protected resources by passing this access token as a parameter, the request goes something like this:
localhost:8080/SpringRestSecurityOauth/api/users/?access_token=8c191a0f-ebe8-42cb-bc18-8e80f2c4238e
4) In case the token is expired, user needs to get a new token using its refreshing token that was accepted in step(2). A new access token request after expiration looks something like this:
localhost:8080/SpringRestSecurityOauth/oauth/token?grant_type=refresh_token&client_id=restapp&client_secret=restapp&refresh_token=7ac7940a-d29d-4a4c-9a47-25a2167c8c49
All the above step are working fine. Now i need to implement this on my client side. So that a particular client can access this call. I am using HTML/CSS as client side technology.
How client can get the access token? Should it be stored in the browser local storage? Or it should be generated every time the rest call is been made?
Any example would help me to proceed further.
I'm implementing my project like you. I use angularjs and get the access token from response json then store it into cookies.
This link provide sample code for you: http://www.baeldung.com/rest-api-spring-oauth2-angularjs. (See Frontend - Password Flow).
Because refresh token should keep secret and the client is html app, you should see this link http://www.baeldung.com/spring-security-oauth2-refresh-token-angular-js for handling refresh token.
For html client, after obtaining access token using refresh token when access token is expired, I use http-auth-interceptor ([http]://witoldsz.github.io/angular-http-auth/) to retry all rest requests failed because of expired access token.
I'm sorry that I have not enough reputation to post more than 2 links.