Reloading or refreshing page removes authorization in vue.js - javascript

I'm using social authentication using the vue-google-oauth2 library. It works fine as I am able to authenticate my self and I receive a token from the backend too.
When initially I log in, and by using a function that is part of the vue-google-oauth2 library that I'm using to check if it says that I'm authorized or not, it gives the following response in my browser's console:
this.$gAuth.isAuthorized
true
When I then refresh my browser page, and since I've placed a debugger command in my code, and I print the same function again,
I get the following response:
this.$gAuth.isAuthorized
false
What can I do to ensure that switching tabs, reloading page or refreshing it won't make this happen? Or is this what is actually supposed to be happening?

Have you looked at saving it in as session data? Im not to familiar how Angular state works, but when you set original state you can look for the session key "authorized" and if it doesnt exist set auth to false, if it exists set it to the value.
localstorage.getItem(item)
and
localstorage.setItem(item)
There is also the option of making a component that handles the google auth and sends it to the state.

From the library documentation for vue-google-oauth page you linked it says you need to send that code back to your backend server to create a token to stay signed in, so it's behaving as expected. From here (https://www.npmjs.com/package/vue-google-oauth2#usage---getting-authorization-code) it states :
The authCode that is being returned is the one-time code that you can
send to your backend server, so that the server can exchange for its
own access_token and refresh_token
In other words, you need to do something with that code to make it persist in your app, otherwise it's just a one-time code, so looks to be expected.

Related

Google api php client code not return refresh token

I have been trying to get refresh token from google api using javascript google client " code " that google return from client side. It returns me the code which i send to the server side. Now from server side i am sending the code to get the refresh token and access token using using google-api-php-client with this call :
https://www.googleapis.com/oauth2/v4/token
While i use the same code from google playground i get the response with refresh token as well but i do not get it from my own server..
This is the code
public function getRefreshToken($code)
{
$client = new Google_Client();
$client->setClientId(config('services.google.client_id'));
$client->setClientSecret(config('services.google.client_secret'));
$client->setRedirectUri('postmessage');
$client->setScopes(config('services.google.scopes'));
$client->setAccessType("offline");
$client->setApprovalPrompt("force");
dd($client->authenticate($code));
dd($client->getRefreshToken());
return ;
}
I have set access type to offline as mentioned in some answers but still i get the response with our refresh token.. this is the response
access_token :"xxxxxxxxxxxxxxxxxxxxxx"
created:1510242052
expires_in:3598
id_token:"xxxxxxxx"
token_type:"Bearer"
Your php code looks fine to me. I suspect your front end javascript, specifically the link to google that it builds, may be to blame. Whether the authorization_code produces a refresh token when redeemed is partially dependent on what parameters are included in the initial link to Google.
As detailed in this answer, the javascript client library uses "client side flow". Normally in a front end app you'd specify response_type=token, but if you specify response_type=code, instead, you'll get a code back. But when redeemed, that code will not produce a refresh token.
For example, a link built by a front end javascript library might look like this:
https://accounts.google.com/o/oauth2/v2/auth?client_id=7xxxxxxxxxxx-xxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=http://localhost:8080/oauth2callback.php&response_type=code&scope=profile
Your back end can redeem the code that comes back, but the response will not include a refresh token. This is by design.
One way to get a code that is eligible for refresh tokens, would be to use the back end PHP client library to build the link, rather than the javascript client library. $client->createAuthUrl() will build a link like this:
https://accounts.google.com/o/oauth2/auth?response_type=code&access_type=offline&client_id=7xxxxxxxxxx-hxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth2callback.php&state&scope=profile&approval_prompt=force
This toy example builds the link this way and does receive refresh tokens.
Note the addition of access_type=offine and approval_prompt=force. After successful authentication, the redirect in this case includes a code that does provide a refresh token when redeemed.
The OAuth 2.0 playground builds an initial link that contains access_type=offline and prompt=consent, which also creates a code that is redeemable for a refresh token.
If this isn't helpful, perhaps you could update the question with the link to google that your front end is building? (With client id redacted, of course)

How to create session inside Loopback app with an AngularJS client?

Here is my problem :
I'm creating a web app with loopback (great framework :) ) with an AngularJS client, everything works well but impossible to reload the page without being disconnected. This behaviour is normal, however I would like to persist the session with a "Remember me" checkbox and just avoid to be disconnect on page reload. The access token is stored in localStorage, I think I have to create a cookie on myself but the main point, how do I avoid disconnection ? And redirection to forbidden page. Then should I do this on server-side or client-side both ? I'm lost actually...
I did start from this application on github if you wish to have a better idea of the project:
https://github.com/strongloop/loopback-getting-started-intermediate
You shouldn't need to create a separate cookie to store the authToken if it's already in localStorage. The part you will need to modify is inside app.js, the .run() block, which checks for the existence of $rootScope.currentUser to determine if you're logged in, which will not be persisted across browser reloads.
The code creates $rootScope.currentUser in Auth.js. The .run() block of app.js simply checks for the existence of $rootScope.currentUser to determine if you are logged in.
So you'll need to change how you detect logged out state from simply checking for $rootScope.currentUser to attempting an actual call to User.getCurrent() or something. If you are logged in, the call will include the auth token in the headers, if not, you'll get a 401 status code response and you can redirect to the login page in that case.

Get an access token without being connected to facebook

I need to retrieve a facebook page's list of posts (feed) using their javascript SDK, just like they explain in their docs: https://developers.facebook.com/docs/graph-api/reference/v2.4/page/feed
/* make the API call */
FB.api(
"/{page-id}/posts",
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
I need it to be my website's "news section", so users should see it even if they are not connected to facebook.
The problem
Cool, but there is a problem... It returns: An access token is required to request this resource.
Holy cow... I'd like to get some access token for you #facebook, but my app doesn't make use of your authentication tools/plugins.
ANYWAY, I tried with FB.getLoginStatus(); but doesn't work, because the only way it can return an access_token is if the user is actually connected to the application. My users may not even be logged to facebook!
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
I've already payed a look to this SO question, but it doesn't solves my problem, simply because there are no such "generic tokens".
I've also read https://developers.facebook.com/docs/facebook-login/access-tokens/ and that also relies on tokens generated through facebook login methods... So, can't I display a list of fb page's posts in my website, without being connected into facebook, hence an application?
ADD: My app is build with angularJS, I'm not dealing with server-side code. I shall rely purely on javascript methods.
You could either use an page or an app access token, but as you'd be using them on the client-side, neither of them are an option.
See
https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens
https://developers.facebook.com/docs/facebook-login/access-tokens#pagetokens
Note that because this request uses your app secret, it must never be made in client-side code or in an app binary that could be decompiled. It is important that your app secret is never shared with anyone. Therefore, this API call should only be made using server-side code.
I'd strongly recommend to build a simple server-side script (PHP for example) to proxy the request to the Graph API. You could then call this via AJAX for example and load the posts asynchronously (and alse get rid of the FB JS SDK!). There is NO way to handle this in a secure manner if you don't want to use FB Login for all of your users (which also doesn't make much sense IMHO).
I think it's straightforward :)
Since pages' posts are always public, it only needs a valid access token to retrieve page posts.
Quoting what you've written:
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
You only require an access token.
My suggestion would be;
- Generate an access token for yourself (no extra permission needed)
- request page-id/posts
This way you don't require other users to be connected to facebook, you can simply requests page-id/posts to retrieve posts with access token you generated for yourself.
I hope it solves your problem :D
TIP: As long as posts are public, you only require a valid access token, it doesn't need to be user or page specific.

Synchronous $resource in AngularJS

I'm in a dead end, because I know that Javascript isn't made for synchronous work, and specially not AngularJS. However, I am in a situation where I am stuck needing it.
I have one main page on the domain "www" (with AngularJS), that calls "api" a lot. Some of the resources on "api" requires authentication, so it returns an 401, which in turn AngularJS picks up and displays a login-box when it sees.
The www-login supports a bunch of login methods and sends the password/oauth/whatever to the "api", which returns a token which the angular app stores in a cookie, and sets in $http.defaults.headers.common['Authorization'] so it can be used to authenticate furter requests to the api.
The same method is also used to get the username that belongs to the api-token.
This works perfectly and solves my design goals. But if the browser is going to an url that requires authentication, the 401 (and hence the login box pops-up). This is (I guess) because angular is not able to populate the Authorization field in the header before the 401 hits the browser..
Solutions?
Have an async=false request using jquery?
Close the login-box when we are done getting the data we want. The login box might flicker...
Store more meta-data about the login (ie, username) in cookies, so we dont haveto do get this information from the server when the app is loading.
??
Is there a better solution? This one time, for this one request, I want async=false in my Angular resource....
The solution I went for (which works perfectly) is to set $http.defaults.headers.common['Authorization'] = 'Token ' + old_api_token;, before the async request. And then overwrite it when the async request is done (if it have changed).

Why the conflicting variables?

I'm getting conflicting results between the facebook javascript SDK and the python requesthandler variables. The Javascript SDK says my user is not logged in, which is correct, while my template variable that comes from the base request handler says that my user is logged in and displays the name of the user. Is there enough info to tell what is wrong or should I paste the code I think is relevant here? A link to the login page that has the error is here. The example I used is called the runwithfriends demo app from facebook and everything with that app worked except using the logic from the app just from a website without requiring the user to be in the iframe of the app.
Plus I can't seem to get the real-time API working. I can only save userID and not refresh user data - why? I have the code but I'm not sure what's most relevant but here's some of the request handler, the relevant code is basically exactly the same as the one from the demo app:
def render(self, name, **data):
logging.debug('render')
"""Render a template"""
if not data:
logging.debug('no data')
data = {}
data[u'js_conf'] = json.dumps({
u'appId': facebookconf.FACEBOOK_APP_ID,
u'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
u'userIdOnServer': self.user.id if self.user else None,
})
data[u'logged_in_user'] = self.user #variable that is the problem
data[u'message'] = self.get_message()
data[u'csrf_token'] = self.csrf_token
data[u'canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
And even more strange, I can also get the application in a state where the javascript SDK says the user is logged in and the template variable logged_in_user says otherwise. Why are the variables conflicting?
Update: Here are screenshots from the strange login flow. I can go to my page and my name from facebook appears:
Then when I go to next page it also looks alright and has my name
But if I log out then I gets in impossible state: my name + logged out
How can I resolve this strange conflict between js and back-end?
Update: Since I only have this problem for one of my apps I can take what works from my other app and integrate. This page seems to work from my other app: http://cyberfaze.appspot.com/file/20985
Your 'user' is probably referring to the Django user not the Facebook user. Make sure you synchronize the two accounts correctly using a custom authentication backend. It's possible that the accounts get out of sync i.e. if the user switches browsers.
Keep in mind that the Facebook Python SDK will stop working after October 1st unless they update it to Oauth2.0 which is unlikely.
I just updated django-facebook-graph to work with the new authentication flow.

Categories