I'm doing a post call to my OAUTH2 authentication with Android, trying to recibe my Bearer Token.
I'm using Kotlin language and i'm doing the post request with Volley.
The problem is that when i do my post request with Postman, it work's perfect, but when i do it in the same way using Volley post, my API REST yells: Invalid Request Exception, missing grant type.
And my android yells: Unexpected response code 400 for http://192.168.1.254:8081/oauth/token
Android call:
private fun loginUser() {
var grant_type = "password"
var username = etUsername.text.toString()
var password = etPassword.text.toString()
val credentials = "angularapp"+":"+"12345"
// Post parameters
// Form fields and values
val params = HashMap<String,String>()
params["grant_type"] = grant_type
params["username"] = username
params["password"] = password
val jsonObject = JSONObject(params)
val request = CustomJsonObjectRequestBasicAuth(Request.Method.POST, Network.API_URL_LOGIN,jsonObject,
Response.Listener{ response->
Log.d("RESPONSEEEE", response.toString())
try {
// Parse the json object here
Log.d("Response" ,response.toString())
val intent = Intent(this, PatientsActivity::class.java)
intent.putExtra(Tags.FLOOR.toString(), ((spiFloor?.selectedItemId!!+1)))
startActivity(intent)
}catch (e:Exception){
e.printStackTrace()
}
}, Response.ErrorListener{
Log.d("ERROR", "VOLLEY ERROR")
},credentials
)
// Add the volley request to request queue
VolleySingleton.getInstance(this).addToRequestQueue(request)
}
// Class to make a volley json object request with basic authentication
class CustomJsonObjectRequestBasicAuth(
method:Int, url: String,
jsonObject: JSONObject?,
listener: Response.Listener<JSONObject>,
errorListener: Response.ErrorListener,
credentials:String
)
: JsonObjectRequest(method,url, jsonObject, listener, errorListener) {
private var mCredentials:String = credentials
#Throws(AuthFailureError::class)
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Content-Type"] = "application/x-www-form-urlencoded"
val auth = "Basic " + Base64.encodeToString(mCredentials.toByteArray(), Base64.NO_WRAP)
headers["Authorization"] = auth
System.out.println(headers.toString())
return headers
}
}
Related
I request your help in solving this pesky problem. I am trying to return the value of 'response' returned by the REST API call, to the calling program. I get null string. Here is the code for your reference. In this code, I want the value of the variable 'response' returned to the caller in onCreate, ie 'restApiResponse' variable.
Thank you very much.
-Vittal
PS: I am a newbie to Kotlin/Android programming.
class OpeningActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_opening)
var restApiResponse = getAPIResponse() // <<<< restApiResponse is empty string
val submitButton = findViewById<Button>(R.id.submitBtn)
submitButton.setOnClickListener() {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
}
fun getAPIResponse() : String {
val myUrl = "YOUR REST API CALL URL"
var jsonObject = JSONObject();
val queue = Volley.newRequestQueue(this);
cpyResponse = StringBuilder();
val stringRequest = object: StringRequest(Request.Method.GET, myUrl,
Response.Listener<String> { response ->
Log.d("A", "VK: Response is: " + response.substring(0, 500))
cpyResponse.append(response.toString())
// .. cpyResponse now has the content of response.
},
Response.ErrorListener { })
{
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers.put("X-API-KEY", "r0IS395C2D8ITjSKV05F610yPXsDQZjllmprr");
return headers
}
}
queue.add(stringRequest)
Log.d("A", "VK: Response is: " + response) // <<<<-- value of response is gone.. it is an empty string!!!!!! :(
return cpyResponse.toString() // <<< --- cpyResource is also empty string
}
I deployed a NLP model as an API with Flask. Now I want to call the API from my simple Android app to process some text and to return a prediction, however when the Android App performs the HTTP request using Volley it does not add the parameters in the URL for some reason. Here is the code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// button
val showButton = findViewById<Button>(R.id.showInput)
// text
val editText = findViewById<EditText>(R.id.editText)
// Setting On Click Listener
showButton.setOnClickListener {
// user input
val text = editText.text
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(this)
val url = "http://192.168.100.12:5000/"
// Request a string response from the provided URL.
val request = object : StringRequest(Request.Method.POST,
url,
Response.Listener {
response ->
editText.setText(response.toString())
},
Response.ErrorListener { error ->
Log.i("error ", error.toString())
editText.setText("Volley error: $it ")
}) {
override fun getBodyContentType(): String {
return "application/json"
}
#Throws(AuthFailureError::class)
override fun getBody(): ByteArray {
val params = HashMap<String,String>()
params.put("text", text.toString())
return params.toString().toByteArray()
}
}
// Add the request to the RequestQueue.
queue.add(request)
// Showing the response
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
}
}
In essence, I am expecting the URL to be "http://192.168.100.12:5000/?text=<insert_text_here>", but the actual URL that the app calls is just "http://192.168.100.12:5000" without the parameters.
I know this because my Flask app returns this error:
AttributeError: 'NoneType' object has no attribute 'lower'
The error response code is 500.
I tested the Flask API with both the browser and Postman and it is working fine, but just in case I will leave the code here:
from flask import Flask,render_template,url_for,request,jsonify
from sklearn.externals import joblib
import traceback
app = Flask(__name__)
#app.route("/",methods=['GET','POST'])
def predict():
try:
tweet = request.args.get('text')
model = open('model.pkl','rb')
model = joblib.load(model)
prediction = model.predict([tweet])
if prediction == [0]:
return 'This tweet does not violate our Community Guidelines'
else:
return 'This tweet violates out Community Guidelines for hate speech'
except:
return traceback.format_exc()
if __name__ == '__main__':
app.run(host = '192.168.100.12',debug=True)
So far I also have tried the code from this post as well as using the GET method with getParams() function instead of getBody() as shown below, but none of them worked.
#Throws(AuthFailureError::class)
override fun getParams(): Map<String, String>? {
val params: HashMap<String, String> = HashMap()
params["text"] = text.toString()
return params
}
Can you please help me solve this issue? I would be very grateful.
I'm creating a login for my application.
I am currently stuck in posting problems to my API
This is my API that which is made to support login.
{
success: false,
message: "Please provide complete and accurate information.",
data: [ ]
}
fun loginUrlSuccess(urlApi : String) {
Log.d("login", urlApi)
authSignin_cgi = gson.fromJson(urlApi, DtoProfile::class.java)
loginsSuccess = authSignin_cgi.success
val queue = Volley.newRequestQueue(context)
val stringReq = object : StringRequest(Request.Method.POST,urlApi,Response.Listener<String>{ response ->
Log.w("response",response)
Toast.makeText(context,"Loging success..",Toast.LENGTH_SHORT).show()
if (loginsSuccess){
Toast.makeText(context,authSignin_cgi.message,Toast.LENGTH_LONG).show()
} else {
Toast.makeText(context,authSignin_cgi.message,Toast.LENGTH_LONG).show()
}
},Response.ErrorListener { error ->
Log.w("error", error.toString())
Toast.makeText(context, "error..$error",Toast.LENGTH_SHORT).show()
}){
override fun getParams(): MutableMap<String, String> {
val param = HashMap<String, String>()
val userEmail = textEmail.text.toString().trim()
val userPassword = textPassword.text.toString().trim()
param["useremail"] = userEmail
param["userpassword"] = userPassword
return param
}
}
queue.add(stringReq)
}
I get an error from the Logcat screen.
So what do I have to do?
04-04 15:31:43.614 8365-8699/com.example.atimeonlin5 E/Volley: [700] NetworkDispatcher.processRequest: Unhandled exception java.lang.RuntimeException: Bad URL {"success":false,"message":"โปรดระบุข้อมูลให้ถูกต้องครบถ้วน","data":[]}
java.lang.RuntimeException: Bad URL {"success":false,"message":"โปรดระบุข้อมูลให้ถูกต้องครบถ้วน","data":[]}
All right , you should try to construct an Url object instead of type String !
You should use an url (like "http://www.google.com"), not a random string. Your urlApi is not url.
Example from doc:
val textView = findViewById<TextView>(R.id.text)
// ...
// Instantiate the RequestQueue.
val queue = Volley.newRequestQueue(this)
val url = "http://www.google.com"
// Request a string response from the provided URL.
val stringRequest = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
// Display the first 500 characters of the response string.
textView.text = "Response is: ${response.substring(0, 500)}"
},
Response.ErrorListener { textView.text = "That didn't work!" })
// Add the request to the RequestQueue.
queue.add(stringRequest)
I have the following request on Insomnia:
Which is working fine!
But, if I try to do this on Android with volley I get a "ServerError":
fun createRequest() {
val params = JSONObject()
params.put("device_key", Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID))
params.put("edition_date", "2018-02-12 00:00:00")
params.put("publication", 1)
val headers = hashMapOf<String, String>()
headers["Authorization"] = "My Token"
headers["Content-Type"] = "application/x-www-form-urlencoded"
getPDF(this, params, headers)
}
fun getPDF(activity: Activity, params: JSONObject, headers: HashMap<String, String>) {
val request = object : JsonObjectRequest(Request.Method.POST, "My URL", params,
Response.Listener {
print("asd")
},
Response.ErrorListener {
it.printStackTrace()
}
) {
override fun getHeaders(): Map<String, String> { return headers } }
request.retryPolicy = DefaultRetryPolicy(0, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT)
Volley.newRequestQueue(activity).add(request)
}
I'm only getting a "ServerError" with a code 500.
What could I be doing wrong in Android? Am I not settings the header correctly? Or could be the params?
In Insomnia you are making a request and the body is a form, while in Android you are trying to send a JSON. Make sure your body consists of key-value pairs and not a JSON object.
I have the following onCreate class in MainActivity and proven to be able to work with my server. It is able to extract out the JWT token
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
submitButton = findViewById<Button>(R.id.btn_submit)
// Volley code is here
val url = "http://192.168.1.8:4000"
submitButton.setOnClickListener({
val pinCode = pin_code.text.toString()
queue = Volley.newRequestQueue(this)
val params = HashMap<String, String>()
params.put("pin_code", pinCode)
val request = object : JsonObjectRequest(Request.Method.POST, url + "/api/employees/token", JSONObject(params),
Response.Listener<JSONObject> { response ->
val token = response
.getJSONObject("data")
.getString("token")
val myIntent = Intent(this, SiteActivity::class.java)
startActivityForResult(myIntent, 0)
},
Response.ErrorListener {
Toast.makeText(this, "That didn't work!", Toast.LENGTH_SHORT).show()
}){
#Throws(AuthFailureError::class)
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers.put("Accept", "application/json")
headers.put("Content-Type", "application/json; charset=utf-8")
return headers
}
}
queue.add(request)
queue.start()
})
}
Unfortunately I have not figured out a way to add the JWT token into the authorized bearer Header for the next SiteActivity. Any suggestion how to make this work? Should I pass the token directly to the next activity or should I use a singleton? Thanks!
Straightly answering question
Put data into Intent with putExtra("token", token).
Take it on the other side with getIntent().getStringExtra("token").
But...
You may want to save token persistently. For example, into SharedPreferences.