Steps:
- Get the Google token
- Send the Google token to your Parse back-end to validate
- Use the validated Google token to create a Parse session token
- Use the Parse session token to allow users to access the app
(1): See the guide: https://developers.google.com/identity/sign-in/android/sign-in
(2): Send the ID token to your back-end server (in this case Parse).
//sending the token to the backend
String backendApiUrlToGenerateSessionToken = your_url_with_cloud_code_to_generate_session_token;
Log.i("URL: ", backendApiUrlToGenerateSessionToken);
RequestQueue newRequestQueue = Volley.newRequestQueue(this);
JSONObject getSessionTokenJsonRequestBody = new JSONObject();
//back-end requires the token and Google client ID to be verified
try {
getSessionTokenJsonRequestBody.put("idToken", idTokenFromGoogle);
getSessionTokenJsonRequestBody.put("GClientId", your_google_client_id); //find it in google-services.json file
} catch (JSONException e) {
e.printStackTrace();
}
final String requestBody = getSessionTokenJsonRequestBody.toString();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, backendApiUrlToGenerateSessionToken, getSessionTokenJsonRequestBody,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
//success callback
//set current user and continue
try {
ParseUser.becomeInBackground(response.getString("result"), new LogInCallback() {
@Override
public void done(ParseUser user, ParseException e) {
if (user != null){
//successfully logged in, take the user to the last page they were on
finish();
}else{
//error
Log.e("Login error: ", e.getMessage());
//show error dialog, prompt user to login again
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//error callback
int statusCode = error.networkResponse.statusCode;
NetworkResponse response = error.networkResponse;
Log.d("Error Response req: ","" + statusCode + " " + response.data.toString());
}
})
{
@Override
public Map<String, String> getHeaders(){
Map<String, String> headers = new HashMap<>();
//post parameters
headers.put("X-Parse-Application-Id", getResources().getString(R.string.parse_app_id));
headers.put("X-Parse-REST-API-Key", getResources().getString(R.string.parse_rest_api_key));
headers.put("Content-Type", "application/json");
return headers;
}
@Override
public byte[] getBody(){
try {
String body;
if (requestBody == null) body = null;
else body = String.valueOf(requestBody.getBytes("utf-8"));
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
};
newRequestQueue.add(jsonObjectRequest);
(3): We've sent the token to our back-end, now we need to validate the token and generate our Parse session token in our back-end. Credit to @Amit http://pastebin.com/133LVYbm included logic to handle logged out users and subsequent login from the same Google account
//generating a random password
function getRandomString(){
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
var string_length = 10;
var randomstring = '';
for (var i=0; i<string_length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum,rnum + 1);
}
return randomstring;
}
Parse.Cloud.define("getSessionToken", function(request, response) {
console.log(request);
console.log(request.params.accessToken);
console.log(request.params.GClientId);
Parse.Cloud.useMasterKey();
//Verifying token (id Token)
var authTokenVerificationURL = "https://oauth2.googleapis.com/tokeninfo?id_token=" + request.params.idToken;
console.log(authTokenVerificationURL);
Parse.Cloud.httpRequest({
url:authTokenVerificationURL
}).then(function(httpResponse){
//Success
//console.log("success httpResponse: " + httpResponse.text);
//Verify if token is generated from our client
var gAudience = httpResponse.data.aud;
if(gAudience == request.params.GClientId) {
console.log("Verified: Token is generated from our app");
var user_emailId = httpResponse.data.email;
var user_username = httpResponse.data.name;
//console.log(user_emailId);
/*
* 1. User signing up for the first time
* 2. User already signed up logging in
*/
//Check if User account exists for the emailId
var query = new Parse.Query(Parse.User);
query.equalTo("email",user_emailId);
query.first({
success: function(user) {
//if the user exists, they could have logged out so no sessionToken is available so we'll need to log them in again
if(user) {
console.log("User found with Username: " + user.getUsername() + ", objectId: " + user.id);
//Generate the Session Token
var sessionToken = user.getSessionToken();
if(sessionToken) {
console.log("SessionToken: " + sessionToken);
response.success(sessionToken);
}else {
//create a new session - login (user can signup then log-out which deletes the session)
var newRandomPassword = getRandomString();
user.set("password", newRandomPassword);
user.save(null, {useMasterKey : true}).then(function(user){
Parse.User.logIn(user.get("username"), newRandomPassword).then(function(user){
var sessionToken = user.getSessionToken();
response.success(sessionToken);
}, function(error){
response.error("Cannot create session");
})
}, function(error){
response.error("Unable to save user data");
});
}
}else {
console.log("User not found, Creating new account for user with emailId: " + user_emailId);
//Create New Account
var nUser = new Parse.User();
nUser.set("username",user_username);
nUser.set("password",getRandomString());
nUser.set("email",user_emailId);
nUser.signUp(null,{
success: function(user) {
console.log("New account created for user with emailID: " + user_emailId);
//Generate the Session Token
var sessionToken = user.getSessionToken();
console.log("SessionToken: " + sessionToken);
response.success(sessionToken);
},
error: function(user, error) {
console.log("Failed to create a new account for emailID: " + user_emailId);
console.log("User: " + user + ", Error: " + error);
response.error(error);
}
});
}
},
error: function(user, error) {
console.log("Query to fetch user failed");
console.log("User: " + user + ", Error: " + error);;
response.error(error);
},
userMasterKey:true
});
}else { //Client has not login from our app
console.log("Google AudienceID: " + gAudience + "\n AppClientId: " + request.params.GClientId);
response.error('Invalid Audience');
}
},function(httpResponse) {
//Error
console.log("Failed httpResponse: " + httpResponse.text);
console.error('Request Failed with response code' + httpResponse.status);
response.error('Failed to verify access token');
});
});
(4) Logic is in step (2) when the requestQueue returns the response we call the becomenbackground() method which saves the session and allows us to get the currently logged in user