How does OAuth know where to send the callback request to? - ruby-on-rails

I am curious about how OAuth knows to send the callback request to my dev machine. For example, when I implement facebook sign-in, and I sign in on my localhost, a request goes out to facebook to authenticate, and when successful, a callback gets sent to my localhost.
I understand I set my domain in the app to be localhost; however, localhost isn't a real registered domain, so how does facebook know which ip address to route my callback to?

When creating the OAuth request, your app also needs to send along a callback URL. Your OAuth gem is more than likely handling this for you. Facebook then redirects back to that callback URL when authentication is done. You can usually customize the callback URL in the OAuth plugins, as well, if you wanted to.

Facebook don't care what the callback url is, it just tell the browser redirect to the url you provided. So the dns lookup is inside your local browser and operating system.

Related

Hiding the IP address and port of my Authorization Server

I consider building a web application and I want to use OAuth2 protocol for the authentication and authorization of users.
I know that Client Server redirects user to Authorization Server to enter username and password. Thus, user can see the URL of login page on browser. I do not want to show what is written on url actually to user due to security reasons. I do not want to expose my Authorization Server with an host name and port to public.
As a solution, I decided Client Server act on behalf of user(browser). That means, client server will send get login page request and return the response (html) coming from Authorization Server. This is simple and I am able to serve login page on Client Server, but I do not know how can I make a request model (client-id, client-secret, redirect-uri, username, password) and where I will send request to (for example "/oauth2/authorize" and then "/oauth2/token") manually. I should apply all the steps in the right order. Can you suggest me this approach? or do you have any idea to achieve hiding the Authorization Server from public? or that is not so important?

Sharing a session between a WKWebView and Safari

I have an iOS app that authenticates for api access and I have a request to throw the user into safari, not a WKWebView but still keep them authenticated.
Is there anyway to securely share the session between an iOS app and full safari?
I have looked into WKProcesspools but I am not sure that will quite do it.
Not sure about WKProcesspools, but you can share the session using Query parmaters.
Format your weburl to include verification token as a query parameter.
When you verify user via API, you must get the token from response. Pass this token as a query parameter in your url and redirect to Safari.
URL - https://www.example.com/page1
URL with token - https://www.example.com/page1?token=asdfv12324fvfropfc23as
Extra care to prevent copy/paste of token:
When creating token, pass IP Address or MAC Address as parameter of your API and based on these addresses you can check if the request is coming from same address. This will take care of the device authentication.

Am I doing this whole API, client app, Oauth/OpenId Connect thing right?

I have some programming experience, but only with PHP and Java enterprise systems. But now I have some ideas about a web app in my new job. Since I am new at this, I would like to share how I have done the whole API in a server, browser app and authentication with Google’s OpenID Connect (I read a lot about Oauth and OpenID Connect, most helpful source was this: https://developers.google.com/identity/protocols/OpenIDConnect).
Server: Laravel - hxxps://coolapp-api.mycompany.com
Client: Angular - hxxps://coolapp.mycompany.com
TL;DR version:
1) User goes to hxxps://coolapp.mycompany.com, gets an Angular app login page. Types in their email, clicks “Sign in with Google”;
2) The app sends the email to hxxps://coolapp-api.mycompany.com/api/sign-in. The server redirects the user to hxxps://accounts.google.com/o/oauth2/auth with all the needed parameters;
3) The user logs in to their Google account, gives my app permission if it’s their first time, and Google redirects them to my server at hxxps://coolapp-api.mycompany.com/sign-in/google/callback. The server checks everything, and if it’s all correct, it creates a JWT token and send a redirect to the client app at hxxps://coolapp.mycompany.com/login/callback?token=JWT-TOKEN
4) The client app gets the token, stores it in local storage, and sends it to the server with every API call
More detailed version:
1) User goes to hxxps://coolapp.mycompany.com, gets an Angular app login page. Types in their email, clicks “Sign in with Google”;
2) The app sends the email to hxxps://coolapp-api.mycompany.com/api/sign-in. The server creates a state token and stores it in cache, associated with the email received. Then the server creates Google’s oauth URL and sends it to the client in the response body. I tried to do it with a HTTP redirect, but Google’s server was responding with an CORS error. The Angular app reads Google’s url from the response and goes there.
3) The user logs in to their Google account, gives my app permission if it’s their first time, and Google redirects them to my server at hxxps://coolapp-api.mycompany.com/sign-in/google/callback?code=AUTHCODE&otherstuff. The server sends the code it received (and all the other needed parameters) to hxxps://accounts.google.com/o/oauth2/token. It receives a id_token with that user’s email and basic info. This app is not public, so I don’t want anyone with a Google Account logging in, only the clients whose emails I added to the server database. So now the server checks if the user’s email in the token is in the database. If it’s not, it sends the user a HTTP 401 - Unauthorized. Then the server checks the state token in it’s cache associated with the email received. If it’s equal to the one received with Google’s redirect, then the server creates another JWT token, but now signed by my server. Finally, it sends a HTTP redirect to hxxps://coolapp.mycompany.com/login/callback?token=JWT-TOKEN with the new token.
4) The client app gets the token, stores it in local storage, and sends it to the server with every API call
Some comments:
Everything is HTTPS;
I added the strictest CSP policies I could to my Laravel server and Angular client;
Currently the app only supports Google’s sign in, while it is in development. Later on I’ll add more.
I made that my server only checks if the user’s email is in the database after they logged in with google because I like that idea that a non-authorized user should have no information about anything. If I made that check before it, during the first round trip, anyone could type an email and discover if that email has an account in my system;
On the last step, when my server sends the JWT token to my client app, I tried sending the token within a cookie, but since my API and my client app have different domains, my client app couldn't read the token. Sending it in the url was the only solution I could find. I tried logging in a popular app that uses Oauth and they did it this way too.
So my question is:
Am I doing something wrong, unsecure, weird?
Thank you all very much
1) Entering an email address every time a user wants to log in is tedious. And it's not needed if the user is already logged in at Google. The user should just click the "Log in with Google" button and get logged in without entering anything. The state parameter can be a random string - not related to the user's email in any way.
2) If you want your backend to process the redirect from Google (using the auth code flow - the backend has the client role in OAuth2 terms), the backend should also initiate a redirect to Google - not by sending data containing the redirect URL. To achieve it, after clicking the "Log in with Google" button, perform a whole page navigation (instead of an XHR request) to /api/sign-in and if the backend returns HTTP 302, the browser will correctly redirect to Google.
3) You should perform request validation (the state parameter) before getting tokens and checking whether the user exist.
On error (access denied), you can consider redirecting the user to an error page with error details instead of returning HTTP 401, since the HTTP code will cause a generic error screen to be displayed to the user. If you want to keep using HTTP codes, I think HTTP 403 Forbidden would be more appropriate.
4) Consider using sessionStorage instead of the localStorage. The sessionStorage gets cleared after closing a browser/tab and it's not shared among tabs. It makes it safer and it allows users to use different identity in different browser tabs.
The tokens your backend issues, is their validity time limited? Is the user required to get a new token after some (short) time period? If not, valid token vales may stay in the localStorage and browser's page history, which can be a security problem.
You can consider using your own OAuth2 auth server (such as RedHat Keycloak) which would accept Google (and later some other providers) for authentication and it would also issue access tokens accepted by your backend.

Why do we need to specify redirect uri two times while using Oauth2

I was wondering why we need to specify the redirect uri both in our code and in google developer console when using Oauth2.I was following this tutorial http://www.tothenew.com/blog/grails-way-of-oauth-2-0-to-access-google-apis-part-1/.
The client may register multiple redirect_uri's with the Authorization Server (i.e. Google) and sending the redirect_uri in the request itself is to let the Authorization Sever know on which one of the registered redirect_uri's the client wants to receive the authorization response.
The redirect_uri parameter is optional by spec: if there's only one registered, then the redirect_uri parameter may be omitted from the request.
The only redirect URI which really matters is the one which you enter into your Google Developer Console. This redirect URI is what Google will use to reconnect with your web application after it has either approved or rejected your authorization attempt.
The reason you are also specifying this redirect URL in your code is to ensure that your application can correctly recognize the incoming redirect request.

Does the Box API OAUTH protocol work from behind a firewall?

I am investigating the possibility of integrating Box API calls from an internal application that sits behind our firewall (it is not exposed to the outside world).
So the question is, if we fire off an authentication request to Box with a callback URI, does Box post back directly to the specified call back URI (so essentially its initiating a new request from Box to the client), or does it send a request back to the client who made the request (standard HTTP request/response), and expect the client to redirect to the call back URI with the tokens?
This might sound an odd question, but during my investigation it appears this is how the Twitter OAUTH protocol works, and if so would help us a lot as we don't want to open up the firewall to the outside world.
See here for info: https://dev.twitter.com/discussions/5801
EDIT: Just found this which seems to suggest that the client will always initiate the request, never the server: https://stackoverflow.com/a/6116736/811108
Many thanks in advance.
A typical user journey for OAuth on Box would like like this:
User's browser requests www.someboxapp.com and the user clicks a login button
User's browser requests the Box authentication URL which begins with https://www.box.com/api/oauth2/authorize
User authenticates on the Box authorize webpage and then the Box site sends a 302 redirect header back to the users browser. This header tells the user's browser to request the the redirect_uri configured by www.someboxapp.com
User's browser requests the redirect URL on www.someboxapp.com - e.g. http://www.someboxapp.com/oauth/redirect_uri
The Box Application running on www.someboxapp.com makes a POST request to https://www.box.com/api/oauth2/token to complete the authentication and get an access token for using the Box API on behalf of the user.
What this means is that if you are running a Box web app on your internal network - you need to make sure that the webserver running the application and the users' machines can connect to https://www.box.com/api/oauth2/
If www.someboxapp.com only exists on your local network - that is fine - the Box API does not need to connect to this host.

Resources