I'm writing an app that uses Google API to authenticate with G+ account in our app.
Currently the customer wants on logging out not only revoke access token for our application but also log out from Google Account used to authenticate.
The solution I've come with was:
/**
* Signs the user out.
*/
HeaderCtrl.prototype.signOut = function() {
// this part revokes token
$http.jsonp('https://accounts.google.com/o/oauth2/revoke?token=' +
accessToken, {
params: {
callback: 'JSON_CALLBACK',
format: 'json'
}
}).success( /* Do stuff on success */);
// this part logs out from google account
$http.jsonp('https://accounts.google.com/logout');
};
The second call works but logs an error on response processing:
Refused to execute script from 'https://accounts.google.com/logout' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
What ways to log out from Google account using AngularJS would you use?
you should not log out your users from Google, they certainly don't want it anyway. Thus, https://accounts.google.com/logout should never be reached.
What you actually want is to make them log out from your website. Revoking the token should be enough for Google authentication's side (your website won't assume the client is logged from to his old token)
Once signOut method is called, just consider he isn't logged any more and end the session in your website.
I think you are tring to do many things that are not related to a "normal logout" experience.
Maybe you should talk to your "customer" to clarify the user stories he/she wants.
A normal logout is one line of js (source) :
gapi.auth.signOut();
If I'm not wrong, what you are doing first in your code (ie revoking the access token), is something that provides an option to remove the association between the account on your app and the google account used for sign-in. As indicated on the link, you must provide this option to the user to follow the g+ developer policies but it's not the same as signing out. Maybe you should try, as a user, these two feature on a site providing a g+ sign-in, such as stack overflow. (Be sure to know your password before revoking the g+ association.)
And for the log out of Google, your app should not do it, and Google should not provide you a way to do it. (And I'd rather think that it's impossible.)
However you can kindly remind your user, after log out, that he/she may need to log out from Google too. Try to log out from stack overflow and look at what happens.
Related
For my firebase web app (using v9 Javascript SDK), whenever a user updates their email, their token expires and they have to log back in. When a token expires, how can I find the reason for it expiring? (e.g. email change, logging out, suspicious activity, etc.) I want to know this so that when the user is redirected to the login page, I can explain to them the reason such as "you have been logged out because your token expired." As of now I have no way of telling whether the token expired from them logging out, or if it was due to an email change. onAuthStateChanged doesn't seem to provide this information since it only provides the User object. I know it's a simple question but I haven't been able to find this answer anywhere. Thanks for any help you can offer :)
I have 3 applications:
An IdentityServer4 API which provides Google authentication and also provides an access token to authorize the resource API.
A simple Resource API which provides some data from DB.
A simple Client in React which have 4 buttons:
Login, for Google auth
Logout
Get data - a simple request with the access token to the Resource API and gets the data from Db
Get user data - returns user profile and token (for debug purpose)
I didn't put any sample code because my problem is not code related, it's knowledge that I'm missing and I ask for guidance.
The workflow is working just fine: the user press the Login button, it is redirected to IdentityServer4 API for Google Auth. From there it is redirected to a Callback Page from the Client and from there to the Index page. I receive the user data and the token, I can request data from the Resource API and it's working.
My problem is: How do I give a Role to the Google Users ?
I don't have users saved in DB. I want three types of Users: SuperAdmin, Admin, Viewer and each of these roles have limited Endpoints which can access.
For limiting their access I saw that I can use Claims-based authorization or Role-based authorization.
So, my question is how ca I give a Google User who wants to login in my app, a specific Claim/Role ? What is the workflow ? I must save it first in DB ? Or there exists a service from Google where I can add an email address and select a Role for that address ?
Thank you very much !
After you get the response from Google in your callback you can handle the user and do what ever you want to do with it. Below are the some typical tasks that you can do in callback that I took from documentation page of identityserver4 link:
Handling the callback and signing in the user
On the callback page your typical tasks are:
inspect the identity returned by the external provider.
make a decision how you want to deal with that user. This might be
different based on the fact if this is a new user or a returning
user.
new users might need additional steps and UI before they are allowed
in.
probably create a new internal user account that is linked to the
external provider.
store the external claims that you want to keep.
delete the temporary cookie
sign-in the user
What I would do is creating an new internal user account that is linked to the external provider and add a role to that user.
If you don't want to save users in db, you can add an extra claim to user in callback method and use that claim in token. and i think this link will help with that.
I'm trying to do an Authorization request following the documentation about it on Microsoft (Getting access on behalf of a user: https://learn.microsoft.com/en-us/graph/auth-v2-user). I'm making the request using Azure's Logic Apps. I already made an app registration in Azure AD and gave it the following permissions (I used the app for a few different requests before so that's why it contains a lot of unnecessary api permissions). I already succeeded in getting access without a user (https://learn.microsoft.com/en-us/graph/auth-v2-service). Now I really don't know what I'm doing wrong, so if anybody has an idea of what it is, please let me know. I will try to explain as carefully as possible using screenshots so you guys get the idea of what I'm trying to do.
On the first screen below you can see the api permission I added to my app registration. For this request I'm only asking authorization for the one with arrow next to it(as you will see later on).
On the second screen you can see the HTTP post request I'm trying to make to the authorize endpoint. I blurred out the Tenant and Client_id for privacy reasons. I only added the required parameters in the body as described by Microsoft. In the scope parameter you can see the api permission I'm asking permission for.
On the third screenshot you can see the output of the request. Instead of getting an Authorization code as requested, I get an HTML body.
When I paste that HTML body into a browser it gives me the following result:
I have no clue what I'm doing wrong. I tripled checked to make sure cookies are enabled, made sure third-party cookies are not disabled and added login.microsoftonline to my trusted websites.
I'm starting to think I'm doing something very simple wrong, but I can't figure out exactly what. Any help is welcome! :D
Sorry can't add a comment so posting as an answer
What you are trying to implement is the Authorization Code grant flow of OAUTH 2.0. In Authorization code grant flow following steps occur
1) User is presented with the scopes that an application requires when accessing certain resources,
2) The user authorizes this. and the user is redirected to a redirect url
3) The application then exchanges the code sent with the redirect url to get the actual token which in this case will be sent to the Microsoft Graph for validation.
4) User then sees the information pulled.
The major crux of Authorization Code grant flow is that "User Authorization is required" This basically means that this flow is used when the call is invoked from a browser client where the user is actually interacting. This flow should not go through the Azure Logic Apps. If you want a service or a daemon to access the resources in that case you should use Client Credentials Grant flow
I have a GAE app, with a URL I restrict to admin:
- url: /admin
script: _go_app
login: admin
I want to PUT or POST to this url with another Go program. What code do I need to write for the client to authenticate to GAE and dev_server.py? Is there a more sensible way that just mocking a web-browser and logging in? I don't need to authenticate or authorise other users, just the admin account for that app.
Is this OAuth? OAuth2? OpenID? Federated? Something else?
I realise this is a bit of an awkward question, since I'm not even sure what the right way to ask it is. However I am able to post to (in this example) /admin using a web browser after logging in with my (admin) gmail account. In that case the request (sent by Chrome) contains the cookies: __cfduid, ACSID (and what I think are Google Analytics IDs). Presumably one of those is responsible for my authentication. How do I get one of those?
And as a side question, if someone MITMs my connection (over http), can they hijack my admin session by reusing that cookie?
GAE likes OAuth2
Have a look at goauth2 . It seems to be the canonical OAuth2 library for Go. They provide a fairly comprehensive example at https://code.google.com/p/goauth2/source/browse/oauth/example/oauthreq.go .
With regards to your question "Presumably one of those is responsible for my authentication. How do I get one of those?", they state:
To obtain Client ID and Secret, see the "OAuth 2 Credentials" section under
the "API Access" tab on this page: https://code.google.com/apis/console/
And, finally, my humble opinion on "if someone MITMs my connection (over http), can they hijack my admin session by reusing that cookie?" is that you should never provide any authenticated connection (nor the connection that does the authentication) over plain http. Especially an admin section.
EDIT: To elaborate on the MITM question, make sure you use HTTPS for any login requests and subsequent requests for the same session, and make sure to set Secure and HttpOnly flags on your cookies.
OAuth2 if you want to use Google Accounts.
See here for details: https://developers.google.com/appengine/docs/go/users/overview (this section specifically deals with admin views)
I've recently tried to switch my app engine app to using openID, but I'm having an issue authenticating with remote_api. The old authentication mechanism for remote_api doesn't seem to work (which makes sense) - I'm getting a 'urllib2.HTTPError: HTTP Error 302: Found', which I assume is appengine redirecting me to the openid login page I've set up.
I guess I'm missing something fairly obvious. Currently my remote_api script has the following in it -
remote_api_stub.ConfigureRemoteDatastore(app_id=app_id, path='/remote_api', auth_func=auth_func, servername=host, secure=secure)
where auth_func is
def auth_func():
return raw_input('Username:'), getpass.getpass('Password:')
Any ideas what I need to supply to remote_api? I guess similar issues would be encountered with bulkloader too. Cheers,
Colin
This was a fun one.
Looking at remote_api, the flow for authentication seems to be something like this:
Prompt the user for Google credentials
Post the credentials to https://www.google.com/accounts/ClientLogin
Parse the auth token out of the response body
Pass the token to https://myapp.appspot.com/_ah/login
Grab ACSID cookie set in the response
Pass the ACSID cookie in subsequent requests that require authorization
I couldn't find a lot of documentation on the new OpenID support, though Nick's blog entry was informative.
Here's the test app I wrote to see how things work:
app.yaml:
handlers:
- url: /remote_api
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
login: admin
- url: /.*
script: test.py
test.py:
class MainPage(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
self.response.out.write("Hi, %s!<hr>admin is %s" % (user.user_id(),
users.is_current_user_admin()))
else:
self.redirect(users.create_login_url('/', None,
'https://www.google.com/accounts/o8/id'))
Flipping my auth mode between Google Accounts and Federated Login, I noticed a few things:
Admin users are correctly recognized by is_current_user_admin() with OpenID
Mixing modes doesn't work. With authentication set to Google Accounts, calling create_login_url with a federated_identity throws a NotAllowedError
An ACSID cookie is still produced at the end of the login process, only it comes from /_ah/openid_verify instead of /_ah/login
So what's happening with remote_api when using Federated Login? If we're using the default appengine_rpc.HttpRpcServer, it's dutifully following the same Google Account authentication process described at the top, only the app no longer considers the ACSID cookie returned by /_ah/login to be valid, so since you're still unauthenticated, you get a 302 redirect to the OpenID login page, /_ah/login_required.
I dunno what the right solution is here. Seems like it would require an API update. Maybe Nick or one of the other Googlers can weigh in.
For now, here's a hacky workaround:
Turn on Federated Login for your app
Make sure you're passing save_cookies=True when calling remote_api_stub.ConfigureRemoteDatastore for your console script
Attempt console authentication and get the 302 error
Login as an admin via your app's web interface
In your browser cookies, find the ACSID cookie for myapp.appspot.com
Find and edit your local ~/.appcfg_cookies file
Replace the ACSID cookie for myapp.appspot.com with the one from your browser
The next time you try to use remote_api, it should work without prompting for credentials. You'll have to repeat the last 4 steps every time the cookie expires, though. You can bump the expiration from 1 day to as high as 2 weeks in the admin console to minimize the annoyance. Have fun!
This is definitely an issue... mark your interest in getting Google to fix this by starring the ticket at http://code.google.com/p/googleappengine/issues/detail?id=3258 and feel free to add any of your workarounds there.
On a related note, we also recognize that the docs are somewhat sparse, so I'm working on an article which hopefully fills-in some of those holes... stay tuned and keep your eyes open at http://code.google.com/appengine/articles
Here's a workaround you can use until there's a more permanent solution in place.