smartcar / android-sdk

Smartcar Android Auth SDK
https://smartcar.github.io/android-sdk
MIT License
19 stars 2 forks source link

Unauthorized redirect_uri: http://localhost:8000/exchange #33

Open Odaym opened 4 months ago

Odaym commented 4 months ago

Hi, I'm following the Android tutorial

After having followed the Backend tutorial and having confirmed that it worked perfectly fine when hit from a browser

Screenshot 2024-07-08 at 22 38 54

The issue I'm facing is that when it's time to do the exchange code to access token, my local server is returning unauthorized redirect_uri as follows

Screenshot 2024-07-08 at 22 40 00

I really appreciate your help and would like you to assist me with this, I'll share my code/config/etc below:

Strings.xml

<resources>
    <string name="app_name">Tesla Login</string>
    <string name="smartcar_auth_scheme">scab94b2dd-5adf-421a-ae89-0b4099563ada</string>
    <string name="client_id">ab94b2dd-5adf-421a-ae89-0b4099563ada</string>
    <string name="smartcar_auth_host">exchange</string>
    <string name="app_server">http://10.0.2.2:8000</string>
</resources>

MainActivity

class MainActivity : ComponentActivity() {
    private lateinit var CLIENT_ID: String
    private lateinit var REDIRECT_URI: String
    private lateinit var SCOPE: Array<String>
    private lateinit var smartcarAuth: SmartcarAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val connectButton = findViewById<Button>(R.id.connect_button)

        CLIENT_ID = getString(R.string.client_id)
        REDIRECT_URI =
            getString(R.string.smartcar_auth_scheme) + "://" + getString(R.string.smartcar_auth_host)
        SCOPE = arrayOf("required:read_vehicle_info")

        smartcarAuth = SmartcarAuth(
            CLIENT_ID,
            REDIRECT_URI,
            SCOPE,
            true
        ) {
            handleResponse(it)
        }

        smartcarAuth.addClickHandler(this, connectButton)
    }

    fun handleResponse(smartcarResponse: SmartcarResponse) {
        val client = OkHttpClient()

        Thread {
            try {
                val exchangeRequest: Request = Request.Builder()
                    .url(getString(R.string.app_server) + "/exchange?code=" + smartcarResponse.code)
                    .build()

                val exchangeResponse = client.newCall(exchangeRequest).execute()
                if (!exchangeResponse.isSuccessful) {
                    throw IOException("Unexpected code $exchangeResponse")
                }

                val exchangeJsonBody = exchangeResponse.body!!.string()
                val exchangeJObject = JSONObject(exchangeJsonBody)
                val accessToken = exchangeJObject.getString("access_token")

                val infoRequest: Request = Request.Builder()
                    .url(getString(R.string.app_server) + "/vehicle")
                    .addHeader("Authorization", "Bearer $accessToken")
                    .build()

                val infoResponse = client.newCall(infoRequest).execute()
                if (!infoResponse.isSuccessful) {
                    throw IOException("Unexpected code $infoResponse")
                }

                val infoJsonBody = infoResponse.body!!.string()
                val infoJObject = JSONObject(infoJsonBody)

                val make = infoJObject.getString("make")
                val model = infoJObject.getString("model")
                val year = infoJObject.getString("year")

                Log.d("SMARTCARRESPONSE", "handleResponse: $make $model and $year")
            } catch (e: IOException) {
                e.printStackTrace()
            } catch (e: JSONException) {
                e.printStackTrace()
            }
        }.start()
    }
}

Android Manifest

<activity
            android:name="com.smartcar.sdk.SmartcarCodeReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="@string/smartcar_auth_host"
                    android:scheme="@string/smartcar_auth_scheme" />
            </intent-filter>
        </activity>

Node server index.js

'use strict';

const express = require('express');
const exphbs = require('express-handlebars');
const smartcar = require('smartcar');

const app = express();
app.engine(
  '.hbs',
  exphbs({
    defaultLayout: 'main',
    extname: '.hbs',
  }),
);

const client = new smartcar.AuthClient({
    mode: 'test',
});

app.set('view engine', '.hbs');
const port = 8000;

// TODO: Authorization Step 1: Initialize the Smartcar object

// global variable to save our accessToken
let access;

app.get('/login', function(req, res) {
  const scope = ['read_vehicle_info'];
  const authUrl = client.getAuthUrl(scope);

  res.render('home', {
    url: authUrl,
  });
});

app.get('/exchange', async function(req, res) {
  const code = req.query.code;

  console.log(code);

  access = await client.exchangeCode(code);

  res.redirect('/vehicle');
});

app.get('/vehicle', async function(req, res) {
  const { vehicles } = await smartcar.getVehicles(access.accessToken);

  const vehicle = new smartcar.Vehicle(vehicles[0], access.accessToken);

  const attributes = await vehicle.attributes();

  res.render('vehicle', {
    info: attributes,
  });
});

app.listen(port, () => console.log(`Listening on port ${port}`));

SmartCar Dashboard

Screenshot 2024-07-08 at 22 43 58

Env Variables exported as well

Screenshot 2024-07-08 at 22 46 02