Google login in thunkable project

I use google auth 2.0 and neocities.org and google app script (backend).
Any questions please ask me below.

1 Like

Nice work!

How does your app know you’ve been logged with google auth? Which api endpoints are you hitting?

What kind of credentials are you passing around this way?

2 Likes

Simple instructions:
This design is divided into two parts, both use google app script as the background.
The webpage part uses the static webpage hosting platform: neocities.org Refer to the google auth2.0 sample code. And after the execution, the token is returned to the background, and the user information is queried by the background, and whether it is valid or not is returned to the webpage, and the webpage is then logged out.
The APP side will send a new login request to the background, the background will randomly send the id back to the APP, the app will open a webpage with parameters, and constantly check whether the login is complete.

@jared Does firebase login not retain login information? Why is firebase database rule not working now (auth.uid!=null), what should I do?

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://apis.google.com/js/platform.js" async="async"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <meta name="google-signin-client_id" content="{yourClientID}">
  
    <title>Login with Google</title>
    <link href="/style.css" rel="stylesheet" type="text/css" media="all">
  </head>
  <body>
  <center>
 <div id ="login">
 <h4>Please login with google first.</h4>
 <div class="g-signin2" data-onsuccess="onSignIn"></div>
 </div>
 </center>
<script>
var url = location.href;
  var getid = "";//參數-code
  //以下取得參數
  if(url.indexOf('?')!=-1)
  {
    //在此直接將各自的參數資料切割放進ary中
    var ary = url.split('?')[1].split('&');
    //此時ary的內容為:
    //ary[0] = 'id=U001',ary[1] = 'name=GQSM'
    
    //下迴圈去搜尋每個資料參數
    for(i=0;i<=ary.length-1;i++)
    {
        //如果資料名稱為id的話那就把他取出來
        if(ary[i].split('=')[0] == 'id'){
            getid = ary[i].split('=')[1];
        }
    }
    }


// 登入之後
function onSignIn(googleUser) {
var id_token = googleUser.getAuthResponse().id_token;
console.log(getid);
var formData = new FormData();
  formData.append('token', id_token);
  formData.append('getid', getid);
	

  
  var name = "";
  var uriGAS = "{you gas url}";
  $("#login").hide();
  fetch(uriGAS, {
    method: "POST",
    body: formData
  }).then(response => response.json())
    .then(result => {
      var login = result.login;
      if(login == true) {
        name = result.name;
        var auth2 = gapi.auth2.getAuthInstance();
        auth2.signOut();
        alert(" Login successfully, please go back to the APP. ");
        window.opener=null;
        window.close();
      }else{
        console.log("error");
        var auth2 = gapi.auth2.getAuthInstance();
        auth2.signOut();
        alert("Login error.");
        $("#login").show();
      }
    }) .catch(err => {
          var auth2 = gapi.auth2.getAuthInstance();
          auth2.signOut();
          alert(err);
          $("#login").show();
  });
}
</script>

  </body>
</html>

html code

Which login flow? For devices?

How are you passing the verification code to the app to get the first access token?

How do you ensure that two users login on at the same time don’t get the wrong persons codes?

What’s happening in the app script?

I see it passes the userID and idtoken to GAS. What happens then?

I took a totally different approach.

1 Like
let ss = SpreadsheetApp.getActiveSpreadsheet();
const commandError = {
  "error": true,
  "errorMessage": "The command is invalid."
}

function doPost(e) {
  let sheet = ss.getSheetByName("user");
  let userToken = e.parameter.token;
  let getId = e.parameter.getid;
  let url = "https://oauth2.googleapis.com/tokeninfo?id_token=" + userToken;
  let response = JSON.parse(UrlFetchApp.fetch(url).getContentText());
  if (response.error != "invalid_token") {
    let googleId = response.sub;
    let email = response.email;
    let name = response.name;
    let picture = response.picture;

    let lastRow = sheet.getLastRow();
    let sheetData = sheet.getRange(2, 1, lastRow - 1, 1).getValues();
    for (let i = 0; i < lastRow - 1; i++) {
      if (sheetData[i][0] == getId) {
        sheet.getRange(i + 2, 2).setValue(googleId);
        sheet.getRange(i + 2, 3).setValue(email);
        sheet.getRange(i + 2, 4).setValue(name);
        sheet.getRange(i + 2, 5).setValue(picture);
      }
    }

    let returnValue = {
      "login": true,
      "id": googleId,
      "email": email,
      "name": name
    }
    console.log(returnValue);
    return ContentService.createTextOutput(JSON.stringify(returnValue)).setMimeType(ContentService.MimeType.JSON);
  }
}

function doGet(e) {
  let sheet = ss.getSheetByName("user");
  let command = e.parameter.command;
  let getId = "";
  let lastRow = sheet.getLastRow();
  let returnValue = {};
  switch (command) {
    case "newLogin":
      getId = makeGetid();
      sheet.getRange(lastRow + 1, 1).setValue(getId);
      returnValue = {
        "error": false,
        "getId": getId
      }
      return ContentService.createTextOutput(JSON.stringify(returnValue)).setMimeType(ContentService.MimeType.JSON);
      break;
    case "checkLogin":
      getId = e.parameter.getid;
      let sheetData = sheet.getRange(2, 1, lastRow - 1, 5).getValues();
      for (let i = 0; i < lastRow - 1; i++) {
        if (sheetData[i][0] == getId) {
          if (!(sheetData[i][1] == "" || sheetData[i][2] == "" || sheetData[i][3] == "" || sheetData[i][4] == "")) {
            returnValue = {
              "error": false,
              "googleId": sheetData[i][1],
              "email": sheetData[i][2],
              "name": sheetData[i][3],
              "picture": sheetData[i][4]
            };
            sheet.deleteRow(i + 2);
          } else {
            returnValue = {
              "error": true,
              "errorMessage": "User is not logged in."
            };
          }
        }
      }
      if (returnValue.error == undefined) {
        returnValue = {
          "error": true,
          "errorMessage": " The getId is invalid."
        };
      }
      return ContentService.createTextOutput(JSON.stringify(returnValue)).setMimeType(ContentService.MimeType.JSON);
      break;
    default:
      return ContentService.createTextOutput(JSON.stringify(commandError)).setMimeType(ContentService.MimeType.JSON);


  }
}
function makeGetid() {
  let aToz = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
  let getId = "";
  for (let i = 0; i < 30; i++) {
    getId = getId + aToz[random(0, 25)];
  }
  getId = getId + Date.now();
  console.log(getId);
  return getId;
}

function random(mn, mx) {
  return Math.floor(Math.random() * (mx - mn)) + mn;
}


This doesn’t work with google login without validating with Firebase using the google idtoken. Requires you to make api calls or use JavaScript solutions.

You may want to be concerned about exposing credentials in your google sheet since it needs to be public for it to work on intakes apps. Is not not an issue?

1 Like

NO NO No I use google login just for email, I use email to login with that email to login in the app.

So the app waits for a new row in google sheets then grabs the email that appears there and then logs into Firebase using that email? What password do you apply! The same for everyone? Is it encrypted if so?

Side note: we are having heavy talks about bringing oauth to the platform as a standard! Would that be helpful to you?

1 Like

I use sheet like this.

No , I use google app script. Get web api whis long id to get your data.
Not every one can get data.

If you say so! As long as you know it’s secure and works!

Does this allow you to access google cal and other services?

If so, how do you get them without the access token? Are you making calls using a service credential in GAS?

For example, I grab access open and refresh token to make other authenticated calls like this.

Would it help you to see an example of how to authenticate with firebase after getting the idToken from google?

1 Like

@jared operation procedure

1 Like