71
votes

I'm trying to wrap my head around oauth with a React Native app and a separate NodeJS/Express API backend. I understand https://github.com/adamjmcgrath/react-native-simple-auth offers authentication for a React Native app and http://passportjs.org/ offers authentication for a NodeJS backend. I'm unsure how to connect these two for authentication for login and access to the API.

I'd like users to login to the React Native app either by email and password or via Facebook/Twitter/Google. Once logged into the app, what do I send to the API to make sure they are authenticated and have access to a specific route?

Here is an example flow to login and see the logged-in user's settings:

  1. User logs into React Native app via email/password or Facebook/Twitter/Google.
  2. User is authenticated
  3. App makes request to GET /api/settings
  4. API verifies user is authenticated and returns that user's settings or API verifies user is not authenticated and returns a 403.
1
This example might help. It demonstrates using Express/Passport.js with React Native to conduct auth operations. >react-native-login is an example React Native project showing how to use a WebView and react-native-cookies to login to your existing backend. >Link: github.com/ryanmcdermott/react-native-loginkdenz

1 Answers

98
votes

There's a whole lot to this question, so much so that it wouldn't all fit in a single SO answer, but here's some tips and a general outline that should broadly fit into what you want to accomplish.

OAuth2 Authorization

From the sounds of it, you are interested in using OAuth 2 to provide social login authorization, and would like to do first-party authentication as an alternative with an email and password. For social logins you will end up using the OAuth 2 Implicit flow to retrieve an access token, which is a widely recognized pattern. Because you are also looking to authenticate users with an email and password, you may want to familiarize yourself with OpenID Connect, which is an extension of OAuth 2 and which explicitly supports authentication in addition to authorization.

In either case, once your user has either submitted an email/password combo or granted permission through the social identity providers, you will receive in response an access token and (optionally) an ID token. The tokens, likely a JWT (JSON Web Token, see jwt.io) will come across as a base64 encoded string that you can decode to inspect the results of the JWT, which will include things like the ID of the user and other details like email address, name, etc.

For more info on the different types of flows, see this excellent overview on Digital Ocean.

Using Tokens for API Authentication

Now that you have an access token, you can pass it along with all requests to your API to demonstrate that you have properly authenticated. You'll do this by passing along the access token in your HTTP headers, specifically the Authorization header, prefacing your base64-encoded access token (what you originally received in response to your authorization request) with Bearer. So the header looks something like this:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh...

On your API's side, you will receive that token, decode it, and then verify the ID and claims in it. Passed as part of the token in the sub property will be the subject, or ID of the user making the request. This is how you identify access and start to do things on your API side with the respective user's rights, perms, etc. It is also important that you validate the access token once you receive it on your API side, to ensure it wasn't spoofed or hand-crafted.

How it looks in RN for Implicit flows

Here's what the general process looks like in React Native for OAuth 2 Implicit flows, which is what you'll use for social identity providers:

  1. User taps one of your social login buttons on React Native UI
  2. Your code that responds to the buttons will build a request URL to those providers, depending on what each wants (because it differs slightly).
  3. Using the Linking API in RN, you will open up that URL in a browser on the device which sends the user off to the social provider for them to do the login/authorization dance.
  4. Once complete, the social provider will redirect the user to a URL you provider. On a mobile device, you will use your own custom URL scheme to move the user from the web view to your app. This scheme is something you register as part of your app, such as my-awesome-app://, and the redirect URL you pass to the social provider could look like my-awesome-app://auth_complete/. See the Linking API docs for how to configure these URL schemes and deep linking.
  5. In the handler for that new URL scheme/deep link, you'll get the tokens passed as part of the URL. Either by hand or using a library, parse out the tokens from the URL and store them in your app. It's at this point that you can start inspecting them as JWTs, and pass them along in the HTTP headers for API access.

How it looks in RN for Resource Owner Password Grant flows

You have the option for your email/password combo for your own accounts of either sticking with the Implicit flow, or switching to the Resource Owner Password Grant flow if your API and app are trusted by each other, meaning that you are making both the app and the API. I prefer the ROPG flow on mobile apps where possible because the UX is much nicer--you don't have to open up a separate web view, you just have them type in their email and password into UI elements directly in the app. So that being said, here's what it looks like:

  1. User taps the email/password combo login button, and RN responds with a UI that includes TextInputs for the email and password
  2. Build a POST request to your authorization server (which may be your API, or may be a separate server) that includes the properly crafted URL and body details that passes along the email and password. Fire this request.
  3. The auth server will respond with the associated tokens in the response body. At this point you can do the same thing previously done in step 5 above, where you store the tokens for later use in API requests and inspect them for relevant user information.

As you can see, the ROPG is more straightforward, but should only be used in highly trusted scenarios.

At the API

On the API side, you inspect for the token in the Authorization header, and as mentioned previously, and if found you assume that the user has been authenticated. It is still good security practice to valid and verify the token and user permissions. If there is no token sent with the request, or if the token sent has expired, then you reject the request.

Hope that helps! There's certainly a ton to it, but that provides a general outline.