OAuth2 Login API Step 3

I’ve successfully made it through the social and OAuth2 login configuration via the documentation, but I’m stuck on Step 3 of the Login with Provider SDK where it seems like I am supposed to run this:

Backendless.UserService.loginWithOauth2("googleplus", accessToken, guestUser, fieldsMapping, stayLoggedIn)
 .then( function( loggedInUser ) {
   })
 .catch( function( error ) {
   });

however I get this error in the console:

app.js:21 Error: GUID: C537369D-DAA5-F760-FF38-3206511E1100
 Error during obtaining user data.
 Response from OAuth2 provider server: Unauthorized
{
  "error": {
    "code": 401,
    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED"
  }
}

    at checkStatus (backendless.js:12815:9)

I believe this last step is needed to tie the google and BE accounts together? …and hopfully send me a full BE User object? I’m just not clear on how to address this error and what I should be doing to “finish” the login process. It seems like Google authenticates me because I get a url with a userToken and userId, but the last step errors out…any thoughts?

Hello @David_Thompson,

I cannot reproduce the issue you’re experiencing. However, I can suggest you try using the following API:

Backendless.UserService.getAuthorizationUrlLink(providerCode: string, fieldsMapping?: object, scope?: string, redirect?: boolean, redirectAfterLoginUrl?: string, callbackUrlDomain?: string)

Usage:

const authorizationURL = await Backendless.UserService.getAuthorizationUrlLink('googleplus')

window.location = authorizationURL

https://backendless.com/docs/js/users_get_authorization_url.html

Hi @stanislaw.grin …thanks for the recommendation, but that is exactly what I am doing. Here is the full code/steps:

const signUpGoogle = () => {
    //const home = "http://localhost:3002/index.html"
    Backendless.UserService.getAuthorizationUrlLink('googleplus').then(authUrl => {
        location.href = authUrl
    }).catch(error => {
        console.error( 'Error: ', error );
    });

    console.log( 'sign up nav' )
}

this takes me to a google login page which works fine. After login i get redirected to the next page and my app.js script runs this function:

Backendless.UserService.loginWithOauth2('googleplus', userToken, null, null, true)
  .then( function( loggedInUser ) {
    console.log( loggedInUser )
  })
  .catch( function( error ) {
    console.error( error )
  });

This seems like the function that needs to be run in Step 3 of the BE documentation to finish the login and return the BE user object, but I get the error referenced above. Should I not be running the function? Is there a better method for setting the current user and getting the full user object back from BE?

Update:

If I manually set the current user using:

Backendless.UserService.setCurrentUser(user, stayLoggedIn): Promise<Backendless.User>;

the function isValidLogin returns a true value…so should I be running this manually? I’m really struggling trying to follow the documentation for WHAT steps/functions need (or should) be run when logging in with Google or Facebook, etc.

Also interesting is that the documentation says the above function returns a Promise, but I get an error if I try to do this:

  Backendless.UserService.setCurrentUser({'user-token':userToken, objectId: userId}, true)
   .then( user => {
     console.log(user);
   })
   .catch( error => {
      console.log(error);
  });

app.js:18 Uncaught (in promise) TypeError: Backendless.UserService.setCurrentUser(...).then is not a function
    at app.js:18:5
    at app.js:64:2
    at app.js:4:126
    at app.js:5:3

so it doesn’t return a Promise then? Because this works…

 var currUser = Backendless.UserService.setCurrentUser({'user-token':userToken, objectId: userId}, true);
  console.log(currUser);

Where is the best source for updated API documentation. I don’t want to just ‘make it work’ in case the documentation is correct and the working code is in error. Makes me nervous someone will update the code and my app will break.

Hi @David_Thompson ,

It looks like you try to use methods from different login strategies.
There are two login strategies to login using OAuth2 providers:

  1. Login without provider SDK.
  2. Login with Provider SDK

getAuthorizationUrlLink method is part of “login without provider SDK” strategy. By calling this method you obtain authorization link which you should open in separate tab/modal/iframe. By this link user will login on the OAuth2 provider side. If login was successful, OAuth2 provider will make redirect to the Backendless server and Backendless will finish authorization. As result of this process you will get object with user data and Backendless auth-token. That object then should be set as current user using setCurrentUser.

loginWithOauth2 is part of “login with provider SDK” strategy. It is helpful when you already have OAuth2 token at hands and simply want to login user to Backendless. Backendless itself do not provide means to extract OAuth2 provider token. It should be done by means of related OAuth2 provider client SDK.

To make things work in your case, you should call setCurrentUser when server returns JSON with user data instead of loginWithOauth2.

Regards, Andriy

Hi @Andriy_Konoz

Thank you for the clarification; that helps move me forward. I’m going to stick with option 1. "Login WITHOUT Providers SDK. The documentation states in step 4 that a successful login “results in the Backendless User object and Backendless user token sent to the application”, but I only get the token and the user objectId. Should I be getting the full user object or just the ID?

Here are the steps as I understand them:

  1. Execute: getAuthorizationLink to get login URL
  2. Login to authentication service provider (google in this case)
  3. If login is successful I get redirected with a URL that contains query string parameters userId and userToken
  4. Use the userId and userToken to setCurrentUser (setCurrentUser does not return a Promise per documentation, but it does return an almost empty user object…no user details)
  5. To get full user details run: getCurrentUser(true)

Now I am completely logged in? …so far this works…but:

  1. When I navigate to another page and run Backendless.UserService.isValidLogin() I am getting a false which (in my case) redirects me to a login page. Why does this function return false? Is there a better way to test if I am logged in? I need to check this at the top of every page…

  2. When I run Backendless.UserService.logout() it doesn’t seem to “deauthorize” my login with google so next time I log in with getAuthorizationLink it sends me straight to the redirect page. Is there another function I need to run to also ‘logout’ of the social login service?

@David_Thompson ,

Should I be getting the full user object or just the ID?

If you specified redirectAfterLoginUrl (and according to your description you did) then you will only get userToken and userIdin query params on page from URL.
In case when mentioned parameter was not provided or null passed you will get full user data object.

  1. Use the userId and userToken to setCurrentUser (setCurrentUser does not return a Promise per documentation, but it does return an almost empty user object…no user details)

It is expected since method only sets user object which you have passed. After this you need to load other user data by calling getCurrentUser(true)

When I navigate to another page and run Backendless.UserService.isValidLogin() I am getting a false which (in my case) redirects me to a login page. Why does this function return false?

Does your call to the setCurrentUser method still looks like this one?

var currUser = Backendless.UserService.setCurrentUser({'user-token':userToken, objectId: userId}, true);

When I run Backendless.UserService.logout() it doesn’t seem to “deauthorize” my login with google so next time I log in with getAuthorizationLink it sends me straight to the redirect page.

You confuses logout on the side of Backendless app with logout on the side of OAuth2 provider.
By calling Backendless.UserService.logout() you will be logged out only from Backendless. It means that auth user token becomes invalid.
What you see in case of Google is kind of “shortcut” made by Google - it remembers that you recently logged in from specific device and it keeps for some time opened session so when you try to log in again Google picks previous session and does not ask about login. Other OAuth2 providers can behave differently. Backendless itself can’t affect this behavior.

Regards, Andriy

yes i have redirectAfterLoginUrl specified on the Backendless config for Google…but not in the function call. The function call I have is this:

Backendless.UserService.getAuthorizationUrlLink('googleplus').then(authUrl => {
        location.href = authUrl;
        
    }).catch(error => {
        console.error( 'Error: ', error );
    });

I tinkered around with different calls and configs (removed redirect in Google config, passed (null, ‘’, etc) through function call and I couldn’t return a full user object. All I was ever able to get was the query params like I mentioned. I’m ok with this, but if you had an example I could use it would save several steps.

Also my call to setCurrentUser was missing the ‘true’ value to stay logged in. I added it back and it fixed the issue with isValidLogin returning false. I was iterating too much and this parameter fell off at some point.

Yes, that makes sense about the logout() explanation, thank you. Essentially I would have to go to a google page and logout from there to “completely” log out.

Hello @David_Thompson,

I’ve just checked and if you retrieve the authorization URL as @stanislaw.grin told:

const authorizationURL = await Backendless.UserService.getAuthorizationUrlLink('googleplus')

without the redirectAfterLoginUrl specified, it will look like this:

https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=95063853XXXXXXX.apps.googleusercontent.com&redirect_uri=https://XXXXX.backendless.app/api/users/oauth/googleplus/authorize&scope=https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email&state=db301f2dXXXXXXX

if you open this url you’ll see the whole user object:

{"lastLogin":1708349135147,"userStatus":"ENABLED","created":1708349040122,"
accountType":"OAUTH","socialAccount":"OAUTH","ownerId":"0899B936XXXXXXXXXX","
oAuthIdentities":[{"oAuthId": "1183XXXXXXXX", "displayName": "User Name",
"providerCode": "googleplus"}],"phoneNumber":null,"name":"User Name",
"___class":"Users","blUserLocale":"en","id":"11833XXXXXX",
"user-token":"88DXXXXXXXXXXX","updated":1708349040146,
"email":"XXXX@gmail.com","objectId":"0899B936XXXXXXXXX"}

Regards,
Olha

I’m sorry I’m not following what you mean by opening the url? I can get the url, but when I open it in a browser it shows me the google login form. I can’t find the user object anywhere. Even after I login I don’t see the user object anywhere. Does it come back as a query parameter or a server response? Maybe it’s returning the object, but I don’t know how to capture it?

Hi @David_Thompson,

what is your application ID?

application ID

0A712AC8-04AB-0261-FF80-964B643D3000

@David_Thompson ,

As I can see in “Login Providers” section for Google you configured redirect URL. In this case, after authoriztion you will be redirected to specified URL with user ID and user auth token in query params.

I’m sorry I’m not following what you mean by opening the url? I can get the url, but when I open it in a browser it shows me the google login form. I can’t find the user object anywhere. Even after I login I don’t see the user object anywhere.

This is beause of filled “redirect URL” field in Google login provider. If you remove it and try again to open that authorization URL in browser, you should receive full user object at the end instead of redirect to your custom page.

Regards, Andriy