I'm in the process of setting up OAuth with Strava API for a React Native project created with expo
version 51.
It's a fairly generic OAuth process, it consists of three steps. It is all outlined in detail in Strava docs for authentication.
Step one:
We need to send GET request to a link:
https://www.strava.com/oauth/authorize
https://www.strava.com/oauth/mobile/authorize
(for mobile devices)
The above GET has to have query params attached (example from docs):
- "client_id" => "1234321" - "redirect_uri" => "https://www.yourapp.com" - "response_type" => "code" - "approval_prompt" => "auto" - "scope" => "activity:write,read"
When GET is executed, the user is taken to Strava to confirm they are happy to authorise my app and give it the requested access specified in the scope
query param. If the user does authorise, Strava API will call the "redirect_uri" link, which should link back to our application.
Now, Strava has a security setup on their server. If you create the above GET with a url that consists of a "redirect_uri" link that does not contain the domain you've set in the Strava APP created on their website, Strava's API will reject your request with the message:
{"message":"Bad Request","errors":[{"resource":"Application","field":"redirect_uri","code":"invalid"}]}
Here's info about it from their docs:
redirect_uri
- required string, in query - URL to which the user will be redirected after authentication.Must be within the callback domain specified by the application. localhost and 127.0.0.1 are white-listed.
To get access to Strava API you need to create an application, and while you do that you are asked to specify the callback domain. They do have some front-end validation setup on the application creation form. They do not allow any URI specification in the input field, simple word e.g. example
is allowed, as well as the whole domain e.g. example.com
or example.app
or even example.app.app
but no http://example.com
it will come back with error: "This field must be just a domain, no slashes or paths".
Now that we have it explained, let's proceed.
React Native generally works for three separate environments: web, android and iOS.
Web
I successfully Authenticated with the web version by specifying a callback that was allowed by the Strava API and then returned to me on the web (in a new tab).
Android (and iOS)
I'll focus on Android because deep linking works the same (I guess?) on both platforms. I've set up my local development with Expo Go and use Development Build that was created with eas
and now have the Android app installed on the physical device with scheme
setup. So if I try to open up a link scheme://home
on my mobile device, it will take me to my app, to the home
screen. I've tested this and it works.
The challenge is in the Strava API callback domain security setup. I can't seem to find a way to supply a working callback url, that will (once the user authorises) take back to my app and allow to process further authentication steps.
Combinations of domains and "redirect_uri" I tried:
"example" (This is set in Strava App)
Callback urls tried when the above domain is set:"example://something" => invalid"example" => invalid"http://example.app" => invalid
Another example:
"example.com"
"example.com://localhost.com?some=param" => invalid"example.com" => invalid"example.com?some=dude" => invalid"localhost" => invalid"http://example.com?authorise" => works"example.com://example.com" => works"localhost://localhost" => works"localhost://example.com" => works
By "works" I mean that Strava does not reject the supplied callback URL based on the security they set up on their end.
Based on the above checks, it seems that we have to use URI in the callback domain. We also have to use a full domain, not just a name. Considering these constraints and how linking back to mobile apps works (e.g. scheme://screen-name), here's my questions:
- How can I successfully redirect the user back to my app, so they can authorise the API?
- Do developers name their screens with "domain.com" to fulfil such security setup and authenticate?
- What is or would be, the best practice in such a case?