Multiple users logged in Dropbox - authentication

I need to log in a user into Dropbox using Core API. Then remember his/her access token and allow logging in with another credentials (looks like a second Dropbox user). But when I make request to https://www.dropbox.com/1/oauth2/authorize it automatically ends up with redirect page with first user's access token giving no chance to enter another credentials. I know I can revoke first access token but then I will not be able to silently come back to first user.
Does anyone know is the possible to implement?

You can set the force_reapprove parameter for the /authorize page to true to prevent the automatic redirect:
https://www.dropbox.com/developers/core/docs#oa2-authorize
Note that the /authorize page is hosted on www.dropbox.com though, so the user will get their www.dropbox.com session, even if force_reapprove=true is set. With that parameter set though, the user has the opportunity to switch accounts, using the dropdown in the upper right of the page, before authorizing the app.
If that's not sufficient for whatever reason, you can try to end the user's www.dropbox.com. The simplest way is to direct them to www.dropbox.com/logout first. Be sure to make it clear to the user what is happening though.
Or, if you control the entire browser, e.g., if it's an embedded web view in your app, you can clear the browser's cookies, which will clear the session, forcing users to log in again.

Related

How to approach conditional rendering SPA page?

Basically,
I have SPA app with JWT authentication. Now my question is, there is a page that has follow button, so on the first load of page, I need to know if user is logged in or not, so I can disable/enable button.
Approach 1: Before page load send access token and if it is successful render like user is logged in, if it fails render like user is logged out
Approach 2: When user is logged in, keep that state in LocalStorage and just check local storage and render page from that
Is it correct to just keep state of logged in user in LocalStorage? I think that is where you should store ID token (if you use them) that only has user profile information?
Of course I will check access token on each request and from response I can change state in LocalStorage. Problem is that on initial load of page, should I check access token server-side before rendering?
If I keep state in LocalStorage than that user will be logged in on that device basically indefinitely, until he clicks "log out" or tokens fail?
Can anybody see potential problems with keeping state in LocalStorage?
It's OK to keep this information in the local storage. I mean, you can keep a variable there, that will just tell you "this user is logged in as userX". You can then safely utilize this information to display information on your page (e.g. Hi userX!). Even if someone manages to steal that information, it doesn't give them much information.
As you said, you will have to check the credentials on every request anyway (access token, session cookie, etc.), so it's not an issue to have this non-sensitive data in the local storage.
You can of course go with approach 1, but in my opinion, it's just adding unnecessary traffic.
If it bugs you that it will seem that the user is logged in for ever, then you can also persist some TTL in the local storage, and after that TTL treat the user as logged out.

How is the access_type=online oauth mode (no refresh token) supposed to work?

This question is has a lot in common to the previous question Google OAuth: can't get refresh token with authorization code (and I won't be offended if it's considered a duplicate) but there are some differences: that question uses the Javascript and PHP libraries, and I'm using neither of those. That question wants to know how to get a refresh token, and I want to know if I should want a refresh token, or how the mode with no refresh tokens is intended to work.
I'm following this guide:
https://developers.google.com/identity/protocols/OAuth2WebServer
The goal is to allow users to upload files from Google Drive to my web application.
I'm not using one of Google's favored programming languages, so I don't have a library abstracting away all the interaction with Google. I need to know what the HTTP requests should actually should look like.
One of the parameters in the authorization request is access_type. The description says
Set the value to offline if your application needs to refresh access tokens when the user is not present at the browser.
I won't need to do that (I'll only want to retrieve a file on my server immediately after the user selects it) so in the spirit of not asking for more privileges than you really need, I used access_type=online. This gives me an access token and no refresh token. I've successfully used the access token to make some requests to Google Drive.
The user comes back the next day and tries to upload another file. While processing this request from the user, I make a request to Google Drive. The access token is expired, so I get a 401. What's supposed to happen next?
My guess is I should pretend this is a completely new user and send them through the full authorization process again. That would mean I have to abort whatever the user was trying to do, redirect them to https://accounts.google.com/o/oauth2/auth with all the parameters (scope, client_id, etc.) and embed enough information in the state parameter that I can resume the original request when the user gets back from their detour.
This seems rather difficult (in particular the part about saving and resuming the state of my application at some arbitrary point). It's a big enough obstacle that it should be explained somewhere. But the description of the access_type parameter didn't say anything about needing to insert authorization redirects everywhere. It just said the user must be "present".
You are using the right implementation. You don't need offline access if you aren't going to make requests when the user is not using the application. The thing is that access tokens expire in 1 hour. So you need to generate new access tokens if a user leaves the application and come back later.
If users have authorized your application, calling this URL with your configuration should return a new valid access token:
https://accounts.google.com/o/oauth2/v2/auth?
scope=scopes&
include_granted_scopes=true&
state=state_parameter_passthrough_value&
redirect_uri=http://oauth2.example.com/callback&
response_type=token&
client_id=client_id

Keycloak - Multi/2FA Factor - OTP - QR Code - Custom Login Screen - Rest API

I have my own Login page where user enters username/password.
This username/password are used to login through Keycloak Rest API.
http://localhost:8080/auth/realms/Demo/protocol/openid-connect/token
input - {username,password,grant_type,client_secret,client_id}
And in response i get access token.
Now i wish to enable Authenticator (Google Authenticator). I have enabled it from backend. Now if user wishes to login thorugh my application, my login page i need to get below details.
1.) Somehow i need to include QR Code that appears on keycloak login page post username/password validation to show on my login screen for the first time login once user enter username/password. So do we have any API which return Keycloak QR code image in response.
2.) Subsequent login i will have OTP field, so need a REST api to pass OTP along with username/password.
Please help with REST API if keycloak has any. Integrating through Javascript.
Similar flow as described in use case 1 here
Just want to use keycloak as a database, doing all operation for me, input will be my screen. I do want redirection of URL's while login in and yet should be standalone deployed.
I've managed to implement this through the rest API of Keycloak. To realize this, you need to extend Keycloak yourself with a SPI. To do this create your own Java project and extend org.keycloak.services.resource.RealmResourceProvider and org.keycloak.services.resource.RealmResourceProviderFactory. You can find more information in the official docs (https://www.keycloak.org/docs/latest/server_development/#_extensions), github examples and other stack overflow posts how to do this.
Once you got this up and running you can implement it like this:
#GET
#Path("your-end-point-to-fetch-the-qr")
#Produces({MediaType.APPLICATION_JSON})
public YourDtoWithSecretAndQr get2FASetup(#PathParam("username") final String username) {
final RealmModel realm = this.session.getContext().getRealm();
final UserModel user = this.session.users().getUserByUsername(username, realm);
final String totpSecret = HmacOTP.generateSecret(20);
final String totpSecretQrCode = TotpUtils.qrCode(totpSecret, realm, user);
return new YourDtoWithSecretAndQr(totpSecret, totpSecretQrCode);
}
#POST
#Path("your-end-point-to-setup-2fa")
#Consumes("application/json")
public void setup2FA(#PathParam("username") final String username, final YourDtoWithData dto) {
final RealmModel realm = this.session.getContext().getRealm();
final UserModel user = this.session.users().getUserByUsername(username, realm);
final OTPCredentialModel otpCredentialModel = OTPCredentialModel.createFromPolicy(realm, dto.getSecret(), dto.getDeviceName());
CredentialHelper.createOTPCredential(this.session, realm, user, dto.getInitialCode(), otpCredentialModel);
}
The secret received with the GET must be send back with the POST. The initial code is the one from your 2FA app (e.g. Google Authenticator). The QR code is a string which can be displayed in an img with src 'data:image/png;base64,' + qrCodeString;
I know this is an old question, but I've recently been looking at something similar, and so thought it would be potentially valuable to share what I have found for others who may be looking into this and wondered what the possibilities are.
TL;DR
You can only really use the existing Keycloak actions to do this or embed the user account management page found at https://{keycloak server URL}/auth/realms/{realm name}/account in an iframe. That's it, I'm afraid. In my opinion it is currently best to just assign actions directly to accounts or use the Credential Reset emails to assign actions; both of these can be done via the Admin API if desired:
Send Credential Reset email containing assigned actions:
https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_executeactionsemail
Set actions directly on the account (include the actions in the requiredActions portion of the user JSON that you send in the body to the endpoint):
https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_updateuser
Background is that as part of a project that I have been working on we wanted to see if we could have an integrated way for users to set up their initial password and OTP device when a new account has been created for them, since the default method of sending them an email from Keycloak using the "Credential Reset" functionality has the limitations that a) it doesn't provide a link to the application itself unless you override the theme, and if you have multiple instances of the application for different users you have no way of knowing which instance to provide the link for, so may have to end up including a list of them, and b) it often doesn't feel truly native to the application, even with changes to the theme. If you're sensible though, I'd suggest you stop and just use this functionality - please see the TL;DR section above for details.
So, in short there is NO API endpoint for receiving a QR code to set up an OTP device. There are two places, however, where the QR code can be retrieved from - the OTP device setup screen when you log in as a user who has had a "Configure OTP" action assigned to their account, and the user's own account management screen.
The first option of the Configure OTP action screen is a non-starter. It only shows up when you log in, and so by definition the user has to log in to Keycloak via the Keycloak login page in order to trigger the page to be displayed. At this point you're already on a Keycloak page instead of one of your app's pages, and so unless you can get very creative with changes to these Keycloak pages via a custom theme, tapping into this page isn't really an option.
The second option is more interesting, but far from ideal. Every user who has logged in has access to an account management page that can be found at https://{keycloak server URL}/auth/realms/{realm name}/account. This page allows you to do things like change your name, password, etc. and it also allows you to add an OTP device if you don't already have one, or delete any existing OTP devices associated with your account. This OTP device tab of the account management page can be reached directly via https://{keycloak server URL}/auth/realms/{realm name}/account/totp.
As I mentioned, there isn't an API that you can access to view the QR code that shows up on this page. The only way it is accessible is via the GET request to https://{keycloak server URL}/auth/realms/{realm name}/account/totp, which returns the HTML for the page I've already mentioned. Okay great, so can we scrape the QR code programmatically and then put it in our own page on our application? Err, no, not really. You see, whilst a lot of the Keycloak API endpoints rightly allow you to send a bearer token (e.g. access token) in the authorization header to access and endpoint, this page will not accept a bearer token as a means of authentication/authorization. Instead it uses a session cookie that is locked down to the Keycloak URL. This cookie is set when you log in to your application via the Keycloak login page, and so is available to this account management page when you navigate to it, having already logged in, and since the account management page uses the same server and domain name as the original Keycloak login page, it has access to the cookie and can let you in. This cookie cannot be sent by your application to e.g. your own REST API to then programmatically call the account management page and scrape the QR code, because your application doesn't have access to it for good security reasons. This might be something you can change in Keycloak somewhere, but if there is I would strongly recommend against changing it.
So if we can't scrape the page from our own server, can we do something on the front-end? Well, as mentioned, your application doesn't have access to the session cookie but if you make a request (e.g. using fetch or axios) in your front-end JavaScript to the account management page then that request will send the cookie along with it, so that could work right? Umm, well actually you will get hit with an error message in this scenario due to CORS. CORS is Cross-Origin-Resource-Sharing and in order to allow the Keycloak page to be accessed then you would have to open up the settings on the server to allow it to be accessed from your website's address. I've seen some articles that look at how you can open up your CORS settings on Keycloak if you wish but I'd be very nervous about doing this. I don't know enough about the internals of Keycloak and how it operates to comment on how much of a security risk this is, but I certainly wouldn't recommend it. There some information here (Keycloak angular No 'Access-Control-Allow-Origin' header is present) on changing the "Web Origins" setting of your application's Keycloak client, but this opens up your application to some serious potential abuse. There is also the MAJOR issue that even if you scraped the QR code, the device isn't actually added to the user's account (even though it appears in the authenticator app) until you enter a code into the page that the QR code is on and click Save. Since there isn't an API endpoint that you can use to complete this operation, I therefore don't think that this option is viable either. I've tried out whether or not you can use the token retrieval endpoint at https://{keycloak server URL}/auth/realms/{realm name}/protocol/openid-connect/token to see if making a request with your username/password/otp code will somehow "register" your device and complete the process, but although you can get a token this way, and it doesn't complain about the otp code, it doesn't actually take any notice of the code because as far as it's concerned the user's account doesn't have a device registered with it. So we have to use the form on the account management page in order to complete this registration process.
So the final way of possibly doing this is.... an iframe. Sorry, yeah it's rubbish but that's all your left with. You can have the iframe point at your account management page, and because the user is logged in then they will be able to see the contents from your application's page. You can use relative positioning, fixed width and height and remove scroll bars to ensure that you ONLY show the QR code and the fields for the one time code, device name, and the Save/Cancel buttons. This, sadly, seems to be the only option at the moment, and due to how nasty and unreliable iframes can be in general - they certainly don't feel native to your application, and you'll need to override your Keycloak theme to get the page in question to look more like your app - I'd recommend steering clear of this and using the standard approach of using Keycloak actions and the Admin API instead.
If you've made it this far, congratulations, you win at Stack Overflow :-)

how login works?

Well, you type username and password in form, hit "OK" button. Then data going to server side and check users database if that user is existed. Then it return user id. And what next?
That data is saved in cookies?
Does it mean, that with every clicked link, site login you to website again?
I mean,
you click some link on site
browser redirect you to that page
site checks your cookies
site grab username and password from cookies
site checks is that data is valid (via connecting to database)
show page to you
Is that correct?
User enters credential.
System validates credential.
Upon successful authentication, server saves user object into session.
System grabs user info from session.
System displays webpage.
Tadaa!! :)
UPDATE
To add a little more...
User visits the secured webpage.
System checks if session contains a user object.
If user object exists in session, allow user through to visit the page.
If user object doesn't exists, redirect user to login page.
You don't need to store user password in the session. In fact, it is highly discouraged. Checking to make sure the user object exists in the session is sufficient.
When the user clicks the logout page, then proceed to invalidate the session... that's it. :)
Almost correct. You rarely go to the database with every request. You usually set a cookie with a expiry date and save the user session and info in memory. So every time a request is made, if the user is not authenticated, you authenticate him, generate and send him a cookie with, say, 5h expiry. So, in the next 5 hours, whenever a request comes in with that cookie, you trust that the user is an authenticated, valid user and you don't have to check the database.
It's not how every site does it nor it is the only way to manage session and cookies but I think it is the most widely used.
You should probably use sessions, but that's pretty much the gist of it. That way the data doesn't accidentally persist.
I mean, for my simple site at home, that's how I do it. But it's still locally hosted, so the security is guaranteed to be crap.
Oh, and no need to check with the database whenever you click on another link -- too much time wasted.
Typically, an application takes advantage of the session that is established between the browser and the web server, and makes a note that that session is "authenticated". "session" is a built in feature of HTTP. If the browser is closed, or after a certain period of time passes, the session is automatically closed. If the user does an explicit logout, the application marks the session as not-authenticated.

Redirecting back to a page after authentication through OpenID, Oauth, or Facebook Connect

I'm allowing users to login to my site with either OpenID, Twitter OAuth or FBConnect. If the user attempts to go to a page that requires them to be logged in, after that user logs in I want to send them BACK to that page. Is there an easy way to accomplish this with all of these or should I simply just write the redirect page to a cookie and upon a successful login send them to that page? I'm using Django so if there are any nice tips or tricks involving that specifically that would be great.
Thanks for the input in advance!
You could thread that parameter (the page they were at) through as a parameter to your return_to. As noted in the spec:
Note: The return_to URL MAY be used as a mechanism for the Relying Party to attach context about the authentication request to the authentication response. This document does not define a mechanism by which the RP can ensure that query parameters are not modified by outside parties; such a mechanism can be defined by the RP itself.
For example:
def sendOpenIDCheck(...):
# after getting an AuthRequest from Consumer.begin
return_to = oidutil.appendArgs(return_to,
{'destination_url': that_place_they_tried_to_go})
return redirect(auth_request.redirectURL, realm, return_to))
def handleReturnTo(request):
# after doing Consumer.complete and receiving a SuccessResponse:
return redirect(request.GET['destination_url'])
If there's some other state you need to track (like POST data), or you have an extraordinarily long URL that you can't fit in as a query parameter, or you need to have the destination_url tampered with by the user, you store that information server-side, send the key as a query parameter instead of a URL, and look it up when they get back.
Not very different from storing it in the session, unless the user's got several simultaneous tabs in one session that run in to this, and then having it in the query helps.
Sadly OAuth and OpenID aren't really aware of your app states (while OAuth WRAP can be). So you have to take the following assumption:
The user will complete the sign-in WITHOUT switching tabs/windows or doing other requests on your site.
Then you can do the following:
Once you detect the access of a protected site, store the full query in the session. This won't work at all if it's a POST request, you have to prepare for this problem (show them a warning site with a lik that they must login first).
Store a timestamp of when this request happend.
On your OpenID callback check whether the session variables are set and redirect the user to the stored query. Check the timestamp (don't redirect if the timestamp is older than 5 minutes or so). After that clear both variables from the session.
This will lead to odd behaviour if the user violates against the assumption, but I don't think there is any way you can circumvent that.