I'm developing an application in which I need an authorization workflow.
I m working on OAuth2 with oauth2orize library.
My applications (client) are frontends written in javascript or java (android).
First, what I need is simply a way to authenticate inside of them and get back an access token. To make it work, I have a resource owner flow.
My problem is that I can't store my secret on my client app cause of security problems. Do you have an idea how should I do it?
In the other hand, how can I make a third party login page? Like "connect trough XXX" and then be redirected on the login page?
The Implicit Grant flow is for public clients operating on a given URL, like Javascript (and there's a way to do it on Android).
You'll make a button "Connect through XXX" and then you redirect the user to XXX to authenticate. When that's done, you get a redirect back with the Access Token in the URL fragment.
Related
That question is hardly related to AppLinks assetlinks.json appears not to be used for validation
I am implementing Oauth2 apps on Android. I would like to do SSO (single sign-on) and I have a concern about AppLink to secure the Autorization Code.
The native app, through the browser, initiate an Authorization Request and then receive an Authorization Response containing the Authorization Code. According to RFC6749#section-4.1.2, the code is passed inside the URL:
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
Authorization Code is a sensitive piece of information because it allows a client to fetch an Access Token and Refresh Token and then access to a protected ressource.
To protect that code, the native app must implement https scheme redirects (RFC8252#section-7.2 & section-8.1). On Android, that must be done using the assetlinks.json file
But according to the related question linked at the top, app links on Android seems not to be 100% secure, because the OS may not verify the https scheme.
In that context, how are we supposed to implement Oauth2 authorization code hook ?
EDIT
According to #benjamin anwser, AppLink is not for security. But, the related threat use-case is the following : a malicious app is installed and uses the "SSO Cookie" to get the Auth Code and exchange it for AT+RT. It seems to me that nothing in the process can prevent that case: if applink is not for security, how does the Authorization Server can be aware that this app is a malicious app ?
Note: By SSO-Cookie, I mean the use of CustomTab to do SSO on Android.
It's not the AppLinks functionality that guarantees security. When you configure the /.well-known/assetlinks.json file it allows a transparent redirect to the application without any user interaction. This means that the modal dialog that usually appears to chose which application the user would like use to handle the link won't pop.
As you stated, this mechanism can be bypassed if the user chooses to handle your link with another app or your app is not yet install. The user needs to go to the phone setting in order to achieve this :
Settings > Apps > choose the application which can handle the Authorization Code link > Open by default > Open supported links in this app > choose Always allowThis way a third party application can catch the information contained in your link, in your case the Authorization Code.
That been said, it's actually the Proof Key for Code Exchange (PKCE) that guarantees security of Authorization Code. Your server must implement this feature in order to mitigate unwanted Authorization Code replays.
A little reminder on the OAuth authorization steps using PKCE :
The client (application) calls the /authorization endpoint with a hashed random string and the method which was used to hash it. The client keeps the random string (not hashed) because it will used in the step 3.
The authorization server checks if user entered a right login/password. If all it's good, it stores the hashed random string and it's hash method which were sent in the request. The server then redirect the user agent to the application with a redirection containing the Authorization Code.
In order to retrieve it's Access Token, the client (application) calls the /token endpoint with random string generated in step 1.
The server receives the /token request, extracts the random string and hashes it with the method stored in step 2. Then the server must checks that this hashed string matches the one stored in step 2. If the strings are the same, the server responds with an Access Token and a Refresh Token, otherwise with an error.
This is how the PKCE ensures that the client that made the /authorization request it's the same client that will make the /token request. So even if a third party app captures your Authorization Code it can't use it to retrieve Acess Tokens.
For more informations see : PKCE (rfc 7636) and OAuth 2.0 for Native Apps (rfc 8252)
I'm developing an app using React Native and I couldn't find any tutorial to authenticate my users against my own service (I think this is called 1st party app). Users need to be able to authenticate with user/password and with their Facebook account as well.
I've been researching about it and find out that I should use Authorization Code Grant Flow which should work in this way:
Create a log-in link with the app's client ID, redirect URL, and state parameters
The user sees the authorization prompt and approves the request
The user is redirected back to the app’s server with an auth code
The app exchanges the auth code for an access token
As I understand all my redirect links should start with myapp://uri opening it in native browser. But I really don't need the step two, or do I? Why should I ask the user for permissions for the same service?
One more thing that I don't understand is that to exchange auth code for an access token I need to pass my Client ID and Client Secret. But I've read that I don't have to store client secrets in native apps since it can be compromised.
How have you initiated your react native app? Via create-react-native-app or Expo XDE or through the react-native init? If either of the first two options, Facebook Auth becomes pretty straight forward. Here's a link to Expo's Facebook Auth Docs. Here's a copy/paste example of what that would look like...
async function logIn() {
const { type, token } = await Expo.Facebook.logInWithReadPermissionsAsync('<APP_ID>', {
permissions: ['public_profile'],
});
if (type === 'success') {
// Get the user's name using Facebook's Graph API
const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}`);
Alert.alert(
'Logged in!',
`Hi ${(await response.json()).name}!`,
);
}
}
This will (by default) attempt to authenticate via 'web', meaning it attempts to log in through a modal UIWebView pop up. There are other methods too, but they're only valid for stand alone apps (see behavior options).
I know you said you wanted to use your own service to do authentication, but I think it might be useful for you to at least go through the Auth0 React Native SDK Tutorial to get an idea how to secure client IDs and secrets as well as get an overall idea of what a good auth flow looks like. Then decide whether to rebuild everything yourself as your own service or whether to use theirs.
OAuth 2.0 is not an authentication protocol, it's for Authorization. That is why you are having problems with step 2. This might be interesting to read.
For your flow I think you have 2 options.
Implicit flow, no client secret. (This would be my first choice)
Use the Authorization Code Grant Flow and don't care about the secret. Do make sure you check on your server if the redirecturl is correct.
So, Here is what I understand about how Google Oauth2 works.
Every application or a website (client) needs to register its project and get a client_id and a client secret.
The client_id and a redirect uri are used by the client to make an authorization request to the auth url on behalf of the user who is logged in.
When this happens, there is a pop-up and the user(resource owner) is prompted to allow or deny access to the user's protected resource for the client.
If the user accepts then the user is redirected to the redirect uri from where the client or the application can get the authorization code.
This authorization code is further exchanged for an access token from the OAUTH URL. This access token is later used in the Api calls the client make.
The problem is with the step 3. I am not running a web app or a website. Rather an application that can make curl function calls. Step 4 and step 5 are doable but, How do I bypass the step 3 as I don't have browser capabilities? Is it even possible?
Also can someone please tell how an android app does it? Because even the android app shouldn't have an inbuilt browser. Thanks in advance
We have the OAuth2 for Devices flow to take care of the problem you are trying to solve See this
The user can authorize the app from a different device that has a web broswer.
Every application or a website (client) needs to register its project and get a client_id and a client secret.
Correction / clarification: Any application that wishes to access private Google data must first be registered on Google Developer console. If the data to be accessed is public then a API key can be used. If the data is private then either Oauth2 credentials must be created or service account credentials.
Oauth2 credentials allow a user to grant an application access to a portion of their data (Denoted by scope) the application is identified by the client id and client secret.
Service accounts would allow for preauthorized access to private data normally owned by the developer working on the application. They do not popup the request for user authentication. Please see my article on this Google Developer console service account I don't want to go into service accounts here as you appear to be concerned with Oauth2.
2 . The client_id and a redirect uri are used by the client to make an authorization request to the auth url on behalf of the user who is logged in.
Correction / clarification: The first step in the Oauth2 dance is to request access from the user. This is done via a web page.
https://accounts.google.com/o/oauth2/auth?client_id={clientid}.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/analytics.readonly&response_type=code
Redirect uri is used to tell the authentication server where to return the authorization code to. In the event this is a web page application it would be the full location to a webpage capable of handling the next steps in the process. As you can see I have not put a web page in. This is in sense localhost. It tells the authentication server to just return the code to where ever it was I just sent my request from. It is used in windows applications and probably android although I am not an android programmer so I am not sure its just an educated guess.
4.If the user accepts then the user is redirected to the redirect uri from where the client or the application can get the authorization code.
Correction / clarification: Its probably your code that's redirecting you. I don't think its the server redirecting you but I may be wrong. The authentication server can send the code were ever you want it would be up to the developer to redirect the user someplace after the exchange.
5.This authorization code is further exchanged for an access token from the OAUTH URL. This access token is later used in the Api calls the client make.
Correction / clarification: access token is only good for an hour and you might also get a refresh token back which can be used to get a new access token.
Addressing your problems
The problem is with the step 3. I am not running a web app or a website. Rather an application that can make curl function calls. Step 4 and step 5 are doable but, How do I bypass the step 3 as I don't have browser capabilities? Is it even possible?
This is going to depend upon which api you are going for and whos data this is. If this is data owned by your users then request access from them save the refresh token and then when you need to access it again in your curl script you can just get a new access token and you have access. Its only the initial authorization you need to bother your users with.
Second option if this is your data that you personally have access to you may be able to user a service account. Service accounts are like dummy users you can preauthorize their access. I could create a service account add it as a user on a folder in my google drive and it would then be able to read and write to my google drive with out that popup window.
Also can someone please tell how an android app does it? Because even the android app shouldn't have an inbuilt browser. Thanks in advance
I am not an android developer I think part of it is magic in the Android SDK the credentials you get for android apps are even different. Cant really help with this one.
Sorry for the misleading title, but here's I want to do:
Say I have an already running website AwesomeWeb, which authenticate its users using username/password combination. Now I want to develop a mobile app AwesomeApp for it, and at the same time, develop and open up its RESTful API - AwesomeAPI.
To keep things simple, I plan to authorize AwesomeAPI using OAuth2, and make AwesomeApp the first client/application.
But I DO wish AwesomeApp to have a simple sign-in process: input username/password -> click the button -> done. In other words, have a 'non-web' feel just like Facebook or Twitter does.
For those 3rd party mobile apps that want to access resources (like username) through AwesomeAPI, it should embed a button somewhere in the app, which opens AwesomeApp to display a 'allow/deny' page when clicked. Again, this is what Facebook and Twitter app doing.
OK, here's the questions:
At step 3, what do I use: webview or doing http stuffs background or just use OAuth2 password grant type? Pros vs. cons?
After step 3, I get an access token for AwesomeApp. But this token CANNOT be used in step 4 to issue an access token for some 3rd party app, am I right? If so, how to achieve step 4?
Appreciate your help a lot!
Notes: I'm not asking for OAuth2 flow or inter-app communication.
Regardless of whether you achieve the step 3 by implementing "Resource Owner Password Credentials" flow defined in RFC 6749 (OAuth 2.0) or by other means, the authentication should be performed in the background. Note that in "Resource Owner Password Credentials" flow, a client application does not access the authorization endpoint but accesses the token endpoint directly, so the authorization UI (which is supposed to be shown at the authorization endpoint) is not displayed.
To achieve the step 4, you have to implement "Authorization Code" flow or "Implicit" flow.
What is the point of using OAuth 2.0 client-side authorization in Android if built-in WebView browser doesn't have access to cookies of default user browser? I mean, if I open some oauth-url (e.g. http://blablabla.com/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=token) in WebView - the user will anyway be prompted to enter his credentials to sign in to "blablabla.com" social network. Because even if he is already signed in with some of his browsers (Opera or Dolphin, or default browser), the WebView browser doesn't know anything about corresponding cookies.
EDIT:
I'll try to make it a bit clearer.
The main goal is to simplify sign-in procedure in my application. I'd like to implement such mechanism that we can see on many web-sites: "Login with... Facebook/Google/Twitter/whatever". And in desktop browser that approach works perfectly, because the end-user is already signed in to aimed service WITHIN THIS BROWSER. So basically to sign-in in to my site all he needs is:
Press button "Sign in with..."
On redirected window/popup press
"Approve/Confirm".
Get redirected back, already being signed-in.
The main benefit is that user doesn't need to enter his email/name/whatever - I've already extracted it from his social-network account.
And I'm wondering how to get same effect on Android. The problem is that, as I can see, we can't let user avoid entering password, because the application (WebView) never knows if he is signed-in to some outer service or not. That's why user anyway will be prompted to enter some of his details and all of OAuth benefits become annihilated.
The workaround depends on what you are trying to do. It's not clear to me, looking at your question again, because you do not explain your use case. Instead you are indirectly asking for something that looks very broad as if you want to maintain an Android system-wide login state that spans over multiple applications using shared cookies.
Due to security reasons that is neither good nor wanted. A rogue app could do whatever it wants to do with existing access tokens requested by other apps or just temper with or read existing cookies created and maintained in other apps.
Assuming you are trying to authorize your own app access to a web service using OAuth 2.0 by letting the user log in with a WebView, you need to implement your own WebViewClient, override its onPageStarted or onPageFinished method and check whether the URL argument matches your redirect URL.
If there is a match you need to extract the access token from the URL string. If there is also a refresh token available, then extract that one, too.
(This however only works for a certain type of OAuth flow, which adds the access token to the redirect URL.)
Now you have at least an access token available. Store that token in the private preferences of your application and use it in your service requests until you get a 401 not authorized error message back from the service. At that point you can use the refresh token if available to request a new access token or you have to show the login WebView again.
If you are trying to access a Google service from your app you may find the article Getting started with the Tasks API and OAuth 2.0 useful.
Have you considered launching the browser externally (non-embedded)?
That will benefit from existing cookies and also give users the trusted UI they are most comfortable with when entering credentials to these services. (in other words - users see the SSL lock, the correct URL in the address bar, etc.)