Auth0 Home Blog Docs

Password authentication in Expo App

Hey guys. I’m having some issues finding the best way to handle Username-Password authentication in my Expo App.

I’ve read the docs a lot, and it seems the only way to do this is by issuing a POST request to my authorization server with a grant_type:password. However, this requires the client_secret which I really don’t want my users to have in their phones.

So the other thing I was thinking was to log in my users from the server side. However, this also brings upon other issues like no brute force protection and not being able to use the PKCE flow (at least I think so).

So what is the best practice for this VERY common scenario? We find the browser based authentication against the UX we want to achieve in our app, so we would really like to keep the user inside the app and being able to introduce their credentials directly inside the app.

Since I’m using Expo, I’m unable to use the react-native-auth0 package as it would require detaching the app.

I know this was asked before but the authorization endpoint specs changed, since it’s now asking for the client_secret which it didn’t ask for before and we would prefer not to use a deprecated endpoint.

Any help would be greatly appreciated.

Thanks!

Hi @henryollh205,

Welcome to the Auth0 Community!

The response to this topic addresses the resource owner password grant risks that you should certainly consider before implementing that strategy.

If you are logging the user in from a secure server a client credential grant should be sufficient, and I’m not sure why this would effect brute force protection.

I don’t personally have much experience with expo, but I can check with the team and see what I can come up with.

In the meantime, giving some feedback to our team about your needs is a useful exercise and one way we evaluate what projects get priority.

I’ll reply with what I find.

Thanks,
Dan

Hi Dan! Thanks for your help.

I read that topic, the thing is that the approach explained for a password grant scenario involves having the client_secret inside the client/expo app. (docs in question).

Doing the same thing server-side involves, according to these docs, to forward the IP address of the user logging in. However, if my auth0 client is set as a Native application, I am not allowed to enable the options necessary according to the before mentioned docs. Since I´m unable to forward the IP address of my users, I technically do not have brute force protection, right?

Also, I believe the client credentials flow is specifically designed for M2M situations, whereas I’m looking for the most secure way to log in my users in a public Expo App using a username/password flow.

Thanks again for your help,
Henry

I was referred this post for more info on the matter

I would take a look at the whole topic. Your best compromise might be having the user login through the browser, which sounds like the Oauth Spec recommendation anyway.

I’ll let you know If anyone else has more info,

Dan

Hey! Thanks for the response.

Using the react-native-auth0 lib is not possible for us because it’s not supported by Expo, so we are forced to use the http API for all the operations.

So in summary, all I’m looking for is a way to log in my users through the http API using username/password. We would prefer not to do it directly in the client since it’ll require to store the client_secret in the expo app. So that’s why I was thinking of a server-side login flow. The problem with this scenario is the impossibility to configure brute-force protection as a Native App that is trying to do server-side login. I know this is like so because auth0 expects me to use a Native SDK, but this is impossible in Expo.

We also need to get a refresh token for biometric login.

I know browser based authentication is recommended but I would really like to try as hard as I can to find a way of doing native login in the app with username/password in a way that does not compromise my app auth0’s client_secret.

Switching my auth0 app from native to regular web application could fix the issue since I would theoretically be able to enable IP forwarding and I should be able to log in my users and receive both the access and refresh token. However, I’m not sure about the implications of such change since the app in question is an Expo App, not a regular web application and Expo Apps should be considered native at the end of the day, since that’s what they are after compiling.

If this is simply impossible I guess we will have to compromise and switch to browser based auth.

Thank you for your kindness,
Henry

Hi @henryollh205

Assuming that you understand the risks of doing email/password login directly from the application, you don’t need a client secret to do the resource owner password grant exchange from a native app.
If you selected the right app type when creating it, the Token Endpoint Authentication Type should be set to None, meaning that the client_secret will not be required when making requests to /oauth/token. You can change the app type and token endpoint authentication type now if you have a different selection now.

This would be conceptually equivalent to creating your own server token endpoint (which would also work without authentication from the app, since like you said native apps can’t keep secrets), without the added complexity (and benefitting from Anomaly Detection).

Do keep in mind that opening the Resource Owner grant to the public means that a rogue application could pretend to be yours, trick the user into typing the credentials, and would be able to obtain a token.

1 Like

Hi Nicolas! Thanks for the reply.

This sounds like great news. However, is it still possible to obtain a refresh token following this approach?

This is my current configuration so I guess I’m good on that side.

So, just to be clear, can I do this?

const response = await this.auth0Api.post("/oauth/token", { // https://tenant.eu.auth0.com/oauth/token
				grant_type: "password",
				username: email,
				password,
				audience: auth0Domain,
				client_id: auth0ClientId,
				//client_secret: auth0ClientSecret,
				scope: "openid profile email offline_access"
			})

And still get the access_token, id_token and refresh token?

EDIT:

I just tried the before mentioned code and it works. Thank you so much. I understand the risk of this flow, but we believe it’s simply the best solution for our specific scenario. I will try to think of an alternative way to implement a browser based auth, but at least I feel a lot more confident now that I know the client_secret is safe.

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.