Decode Token JWT android kotlin? - android

I have a token like this:
hereeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcGVyYWRvciI6eyJpZCI6NzAsIm5vbWUiOiJERUlWSVRJIiwidXN1YXJpbyI6IkRFSVZJVEkifSwiaWF0IjoxNjI5ODEyNDA1fQ.JqzQnFSbG6gFsnlJu3-bezxZ_N5e5FEzc9QvpRGu0u4
hide it:
alg: "HS256",
typ: "JWT"
}.
operador: {
id: 20,
nome: "JOAO",
usuario: "JOAO"
},
iat: 1629812405
}
Question is how do I get on android kotlin only user id to use in certain tasks?

You could use this,
https://github.com/auth0/JWTDecode.Android
Assuming the iat value is the user id,
var jwt: JWT = JWT(YOUR_TOKEN_STRING)
var claim: Claim = jwt.getClaim("iat")
//or as a string
var claim: String = jwt.getClaim("iat").asString()

I just fix the issue thanks to this:
private fun decodeToken(jwt: String): String {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return "Requires SDK 26"
val parts = jwt.split(".")
return try {
val charset = charset("UTF-8")
val header = String(Base64.getUrlDecoder().decode(parts[0].toByteArray(charset)), charset)
val payload = String(Base64.getUrlDecoder().decode(parts[1].toByteArray(charset)), charset)
"$header"
"$payload"
} catch (e: Exception) {
"Error parsing JWT: $e"
}
}
Then :
val mDecode = decodeToken(mToken)
val test = JSONObject(mDecode).getString("operador")
val mDecodeTokenOk = JSONObject(test).getString("id")
/** SALVANDO ID_OPERADOR */
mSharedPreferences.saveString(WmsConstantes.ID_OPERADOR,mDecodeTokenOk)
Log.e("------------------>", mDecodeTokenOk.toString());

You don't have to install any libraries. You can try something like this.
Class(s) reflecting your JWT payload
data class JwtPayload(
#SerializedName("iat")
val iat: Int,
#SerializedName("operador")
val operador: Operador
)
data class Operador(
#SerializedName("id")
val id: Int,
#SerializedName("nome")
val nome: String,
#SerializedName("usuario")
val usuario: String
)
You can use this class as a wrapper for your token
class Jwt(private val token: String) {
private val userData: JsonObject by lazy {
val userData = String(Base64.decode(token.split(".")[1], Base64.DEFAULT), StandardCharsets.UTF_8)
JsonParser.parseString(userData).asJsonObject
}
fun getUserData(): JwtPayload{
gson.toJson(userData, Jwt::class.java)
return gson.fromJson(userData, JwtPayload::class.java)
}
fun isExpired(): Boolean {
return userData.asJsonObject.get("exp").asLong < (System.currentTimeMillis() / 1000)
}
companion object {
#JvmStatic
private val gson = Gson()
}
}
Usage
val token = Jwt("YOUR_TOKEN")
val operatorID = token.operator.id

Related

Json array is being converted to string when sending data to api. how to remove it?

"[[{"NameOfNote":"P","Height":"0","Alteration":"100","Frequency":"0.0","Finger":"0","String":"0","Time":"16","Dotted_Note":"0","ToBeDisplayed":"true"},{"NameOfNote":"P","Height":"0","Alteration":"100","Frequency":"0.0","Finger":"0","String":"0","Time":"16","Dotted_Note":"0","ToBeDisplayed":"true"}],[{"NameOfNote":"P","Height":"0","Alteration":"100","Frequency":"0.0","Finger":"0","String":"0","Time":"16","Dotted_Note":"0","ToBeDisplayed":"true"},{"NameOfNote":"P","Height":"0","Alteration":"100","Frequency":"0.0","Finger":"0","String":"0","Time":"16","Dotted_Note":"0","ToBeDisplayed":"true"}]]"
Above is my output
Below is my implementation
var mainJson = JSONArray()
for(i in 0..song_result.size-1){
var innerJSONArray = JSONArray()
for (j in 0..song_result[i].size -1){
var obj = JSONObject()
try {
obj.put("NameOfNote", song_result[i][j].NameOfNote)
obj.put("Height", song_result[i][j].Height)
obj.put("Alteration", song_result[i][j].Alteration)
obj.put("Frequency", song_result[i][j].Frequency)
obj.put("Finger", song_result[i][j].Finger)
obj.put("String", song_result[i][j].String)
obj.put("Time", song_result[i][j].Time)
obj.put("Dotted_Note", song_result[i][j].Dotted_Note)
obj.put("ToBeDisplayed", song_result[i][j].ToBeDisplayed)
} catch (e: JSONException) {
e.printStackTrace()
}
innerJSONArray.put(obj)
}
mainJson.put(innerJSONArray)
}
json is not encoded well let me solve your problem
add the gson lib from here
add this class
data class Root (
#SerializedName("NameOfNote") val nameOfNote : String,
#SerializedName("Height") val height : Int,
#SerializedName("Alteration") val alteration : Int,
#SerializedName("Frequency") val frequency : Double,
#SerializedName("Finger") val finger : Int,
#SerializedName("String") val string : Int,
#SerializedName("Time") val time : Int,
#SerializedName("Dotted_Note") val dotted_Note : Int,
#SerializedName("ToBeDisplayed") val toBeDisplayed : Boolean
)
Call this method
val obj= Root(nameOfNote = "name",height = 9,alteration = 7,frequency = 7.8,finger = 7,string = 7,time = 8,dotted_Note = 9,toBeDisplayed = false)
val json= Gson ().toJson(obj)
You can do this in for loop just rember to add in string dont replace

How to send POST with json using Retrofit?

I'm Struggling how to send POST with json using Retrofit2.
like this:
{
"user_available_id": 702,
"teacher_id" : 3207,
"schedule" : [{
"event_id" : 47533,
"schedule_time" : "2020-11-30 07:00:00",
"status" :1
},
{
"event_id" : 47532,
"schedule_time" : "2020-11-30 06:30:00",
"status" :1
}]
}
I'm suppose send post like that. And I wonder is it possible to send like that or there is another way. can you kindly tell me if there is another way. btw here's how I try to send it
CreateSchduleAPI.kt
#POST("schedule/student-create")
#Headers("Accept: application/json")
#SerializedName("data")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: String
): Response<ScheduleModel>
And the Model
ScheduleModel.kt
#Parcelize
data class ScheduleModel(
#field:SerializedName("user_available_id")
var userAvailableId: String? = null,
#field:SerializedName("schedule")
var schedule: ArrayList<schedule?>? = null,
#field:SerializedName("teacher_id")
var teacherId: String? = null
) : Parcelable
#Parcelize
data class schedule(
#field:SerializedName("event_id")
var eventId: String? = null,
#field:SerializedName("schedule_time")
var scheduleTime: String? = null,
#field:SerializedName("status")
var status: String? = null
) : Parcelable
First
private suspend fun getMultiSlotJadwal(id: String, date: String) {
jamList.clear()
val networkConfig =
NetworkConfig().getTeacher().getTeacherScheduleAvailability(token, id, date)
if (networkConfig.isSuccessful) {
if (networkConfig.body()!!.availability!!.isEmpty()) {
binding.rvSlot.visibility = View.GONE
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
} else {
for (slot in networkConfig.body()!!.availability!!) {
//convert tanggal start ke millis
val tanggalSlot = slot!!.start!!.toDate().formatTo("yyyy-MM-dd HH:mm")
val tanggalInMillis = convertToMillis(tanggalSlot)
//ambil tanggal sekarang
val myFormat = "yyyy-MM-dd HH:mm" // format tanggal
val calendar = Calendar.getInstance()
val time = calendar.time
val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
val curdate = sdf.format(time) //diconvert ke tanggal local
val curDateinMillis = convertToMillis(curdate) // convert ke millis
val hasilDate = tanggalInMillis - curDateinMillis
val tanggalJam = hasilDate / 3600000 //diubah dari millis ke jam
if (tanggalJam >= 6) {
jamList.add(slot)
val sortJamList = jamList.sortedBy { jamList -> jamList.start }
binding.rvSlot.visibility = View.VISIBLE
binding.rvSlot.adapter = SlotJamAdapter(sortJamList) {
teacher_id = it.teacherId.toString()
scheduleModel.teacherId = teacher_id
scheduleModel.userAvailableId = user_avalaible_id
scheduleItem.scheduleTime = it.start.toString()
scheduleItem.status = "1"
scheduleItem.eventId = it.id.toString()
scheduleList.add(scheduleItem)
scheduleModel.schedule = scheduleList
itemClicked = true
changeBackgroundButtonSesi2()
}
}
}
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Jam tidak tersedia",
Toast.LENGTH_SHORT
).show()
}
}
}
Second
private suspend fun createSchedule2Sesi() {
val jsonSchedule = Gson().toJson(scheduleModel)
val networkConfig = NetworkConfig().createSchedule().createScheduleSesi2(
token,
jsonSchedule
)
try {
if (networkConfig.isSuccessful) {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Berhasil",
Toast.LENGTH_LONG
).show()
startActivity(Intent(this, MainActivity::class.java))
finish()
}
} else {
Handler(Looper.getMainLooper()).post {
Toast.makeText(
this,
"Pembuatan Jadwal Gagal, Cek Koneksi",
Toast.LENGTH_LONG
).show()
}
}
}catch (e:Exception){
Log.e(TAG, "createSchedule2Sesi: ${e.message}", )
}
}
Thank you in advance
Retrofit allows you to use your Kotlin object as a parameter of a call. It will take care of the json serialisation itself if you use GsonConverterFactory when building your Retrofit instance.
That will allow you to change the definition of your endpoint as below
#POST("schedule/student-create")
suspend fun createScheduleSesi2(
#Header("Authorization") token: String?,
#Body createSchedule: ScheduleModel
): Response<ScheduleModel>

Android: JSON object getString

I use this JSON https://api.github.com/users
I need to get string name, followers, following, and more. But on the program says "No value for name". I think I need to go to a specific user example: https://api.github.com/users/mojombo to getting that info, but I don't know-how.
And I using loopj library.
Here's My Code
private fun getDataGitDetail() {
progressBar.visibility = View.VISIBLE
val client = AsyncHttpClient()
client.addHeader("Authorization", "token 6fe9dff2e5e43d25eb3abe9ff508a750b972f725")
client.addHeader("User-Agent", "request")
val url = "https://api.github.com/users"
client.get(url, object : AsyncHttpResponseHandler() {
override fun onSuccess(
statusCode: Int,
headers: Array<Header>,
responseBody: ByteArray
) {
progressBar.visibility = View.INVISIBLE
val result = String(responseBody)
Log.d(TAG, result)
try {
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val username: String? = jsonObject.getString("login")
val name: String? = jsonObject.getString("name")
val avatar: String? = jsonObject.getString("avatar_url")
val company: String? = jsonObject.getString("url")
val location: String? = jsonObject.getString("url")
val repository: Int = 0
val followers: Int = 0
val following: Int = 0
listData.add(
Data(
username,
name,
avatar,
company,
location,
repository,
followers,
following
)
)
}
showRecyclerList()
} catch (e: Exception) {
Toast.makeText(this#MainActivity, e.message, Toast.LENGTH_SHORT)
.show()
e.printStackTrace()
}
}
override fun onFailure(
statusCode: Int,
headers: Array<Header>,
responseBody: ByteArray,
error: Throwable
) {
progressBar.visibility = View.INVISIBLE
val errorMessage = when (statusCode) {
401 -> "$statusCode : Bad Request"
403 -> "$statusCode : Forbidden"
404 -> "$statusCode : Not Found"
else -> "$statusCode : ${error.message}"
}
Toast.makeText(this#MainActivity, errorMessage, Toast.LENGTH_LONG)
.show()
}
})
}
The current response you are getting does not contain a key name in the JSONObject.
If you want the Name of all the users you will have to go to each users endpoint in the api. You'll need to make another request inside your for loop that gets datafrom an endpoint like https://api.github.com/users/mojombo
val jsonArray = JSONArray(result)
for (i in 0 until jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(i)
val username: String? = jsonObject.getString("login")
//Make the request here using "https://api.github.com/users/" + login
You can then choose to get the rest of the data from either the first response or the 2nd one as both contain that information.
I hope this helps.
No need for a JSON array, cz API https://api.github.com/users/mojombo is JSON Object.
Example:
client.get(url, object : AsyncHttpResponseHandler() {
override fun onSuccess(statusCode: Int, headers: Array<Header>, responseBody: ByteArray) {
try {
//parsing json
val result = String(responseBody)
val responseObject = JSONObject(result)
textView2.text = responseObject.getString("login")
textView3.text = responseObject.getString("name")
textView9.text = responseObject.getString("location")
desc.text = responseObject.getString("company")
view?.let { Glide.with(it).load(responseObject.getString("avatar_url")).into(imageView2) }
} catch (e: Exception) {
Log.d("Exception", e.message.toString())
}
}
}

Android Kotlin save data class in Firebase Database

I am working on an Android application in Kotlin which integrate Firebase.
Now I want to store my data (Kotlin data class) into Firebase Database.
Data Classes:
#Parcelize
data class Trip(
val fromAddress: String,
val toAddress: String,
val fromLocation: String,
val toLocation: String,
val orderUid: String
) : Parcelable
#Parcelize
data class Order(val trip: Trip, val date: Date, var status: OrderStatus, val userUid: String) : Parcelable {
var pickUpDate: Date? = null
var dropOffDate: Date? = null
var price: Double? = null
}
Fireabase Database write operation:
fun createNewOrder(
fromAddress: String,
toAddress: String,
fromLocation: Location,
toLocation: Location
) {
val fromGeoLocation = fromLocation.convertToGeoLocation()
val toGeoLocation = toLocation.convertToGeoLocation()
val userUid = sharedPreferences[CURRENT_USER_UID_KEY, ""]!!
val orderKey = databaseReference.child(DB_ORDERS_KEY).push().key
val tripKey = databaseReference.child(DB_TRIPS_KEY).push().key
val trip = orderKey?.let { createNewTrip(fromAddress, toAddress, it) }
val order = trip?.let { Order(it, Date(), OrderStatus.PENDING, userUid) }
if (trip != null && order != null && !userUid.isNullOrEmpty()) {
ordersGeoFire.setLocation(trip.fromGeoLocation, fromGeoLocation)
ordersGeoFire.setLocation(trip.toGeoLocation, toGeoLocation)
val allData = mutableMapOf<String, Any>()
allData["/$DB_TRIPS_KEY/$tripKey"] = trip?.convertToMap()
allData["/$DB_ORDERS_KEY/$orderKey"] = order?.convertToMap()
allData["/$DB_USERS_KEY/$userUid/$DB_ORDERS_KEY/$orderKey"] = true
databaseReference.updateChildren(allData)
}
}
I received this error:
com.google.firebase.database.DatabaseException: No properties to serialize found on class kotlin.Unit
Any suggestions?
The problem in your code is that the fileds inside your Trip class are not initialized. A recommended way in which you can create your model class would be:
class Trip(
val displayName: String = "",
val email: String = "",
val photoUrl: String = "",
val userId: String = ""
)
This is only what you need. And a way to create a new object of your Trip class, would be:
val trip = Trip(displayName, email, photoUrl, userId)
It was my mistake, because I was forget to add return type in my extensions convertToMap functions. Now they look like this:
fun Trip.convertToMap(): MutableMap<String, Any> {
val map = mutableMapOf<String, Any>()
map["fromAddress"] = fromAddress
map["toAddress"] = toAddress
map["fromGeoLocation"] = fromGeoLocation
map["toGeoLocation"] = toGeoLocation
map["orderUid"] = orderUid
return map
}
And also thanks to #Alex Mamo for his answer, it helps me in my investigation.
Now my code looks like this and works fine:
#Parcelize
data class Trip(
var fromAddress: String = "",
var toAddress: String = "",
var fromGeoLocation: String = "",
var toGeoLocation: String = "",
var orderUid: String = ""
) : Parcelable
#Parcelize
data class Order(
var trip: Trip? = null,
var date: Date? = null,
var status: OrderStatus? = null,
var userUid: String = ""
) : Parcelable {
var pickUpDate: Date? = null
var dropOffDate: Date? = null
var price: Double? = null
}
fun createNewOrder(
fromAddress: String,
toAddress: String,
fromLocation: Location,
toLocation: Location
): LiveData<Order> {
orderLiveData = MutableLiveData()
orderLiveData.value = null
val userUid = sharedPreferences[CURRENT_USER_UID_KEY, ""]!!
val orderKey = databaseReference.child(DB_ORDERS_KEY).push().key
val tripKey = databaseReference.child(DB_TRIPS_KEY).push().key
val trip = orderKey?.let { createNewTrip(fromAddress, toAddress, fromLocation, toLocation, it) }
val order = trip?.let { Order(it, Date(), OrderStatus.PENDING, userUid) }
if (trip != null && order != null && !userUid.isNullOrEmpty()) {
val allData = mutableMapOf<String, Any>()
allData["/$DB_TRIPS_KEY/$tripKey"] = trip.convertToMap()
allData["/$DB_ORDERS_KEY/$orderKey"] = order.convertToMap()
allData["/$DB_USERS_KEY/$userUid/$DB_ORDERS_KEY/$orderKey"] = true
databaseReference.updateChildren(allData) { databaseError, databaseReference ->
if (databaseError == null) orderLiveData.value = order
}
}
return orderLiveData
}
Hope this will be helpful

Android (Kotlin) - How do I wait for an asynchronous task to finish?

I am new to Android and Kotlin and am currently working on a centralized API router class.
To achieve this I am using the Fuel Framework.
For the doAsync function, I use the Anko for Kotlin library.
To retrieve an authorization token from the API I currently use this method:
private fun Login(username: String, password: String, callback: (Map<Boolean, String>) -> Unit) {
"/auth/token.json".httpPost()
.header(mapOf("Content-Type" to "application/json"))
.body("""{"username":"$username", "password":"$password"}""", Charsets.UTF_8)
.response { request, response, result ->
request.headers.remove("Accept-Encoding")
when (result) {
is Result.Failure -> {
// val data = result.get()
val ex = result.getException()
val serverResponseJson = response.data.toString(Charsets.UTF_8)
var exceptionMessage = ex.message
val jelement = JsonParser().parse(serverResponseJson)
val jobject = jelement.asJsonObject
val serverResponseError = if (jobject.has("Error")) jobject.get("Error").asString else jobject.get("detail").asString
callback(mapOf(Pair(false, serverResponseError)))
}
is Result.Success -> {
val data = result.get()
val returnJson = data.toString(Charsets.UTF_8)
Log.println(Log.ASSERT, "RESULT_LOGIN", returnJson)
callback(mapOf(Pair(true, returnJson)))
}
}
}
}
I invoke this login method at
val btnLogin = findViewById<Button>(R.id.btn_login)
btnLogin.setOnClickListener { _ ->
doAsync {
val username = findViewById<EditText>(R.id.input_username_login)
val password = findViewById<EditText>(R.id.input_password_login)
Login(username.text.toString(), password.text.toString()) {
// Request was successful
if (it.containsKey(true)) {
// Parse return Json
// e.g. {"id":"36e8fac0-487a-11e8-ad4e-c471feb11e42","token":"d6897a230fd7739e601649bf5fd89ea4b93317f6","expiry":"2018-04-27T17:49:48.721278Z"}
val jelement = JsonParser().parse(it.getValue(true))
val jobject = jelement.asJsonObject
// save field for class-scope access
Constants.token = jobject.get("token").asString
Constants.id = jobject.get("id").asString
}
else{
Toast.makeText(this#LoginActivity, it.getValue(false), Toast.LENGTH_SHORT).show()
}
}
}[30, TimeUnit.SECONDS]
var test = Constants.id;
}
In a separate Constants class, I store the token and id like this:
class Constants {
companion object {
val baseUrl: String = "BASE_URL_TO_MY_API"
val contentTypeJson = "application/json"
lateinit var STOREAGE_PATH: String
// current user details
lateinit var id: String
lateinit var token: String
lateinit var refresh_token: String
// logged in User
lateinit var user: User
}
How do I make sure that the test variable is set after the asynchronous task is done? Currently, I run into
lateinit property id has not been initialized
I have come across the option to limit the task to a timeout such as I have done with [30, TimeUnit.SECONDS], unfortunately, this did not help.
Thanks for the help! Cheers.
I think the problem is where you want to access the result:
val btnLogin = findViewById<Button>(R.id.btn_login)
btnLogin.setOnClickListener { _ ->
doAsync {
val username = findViewById<EditText>(R.id.input_username_login)
val password = findViewById<EditText>(R.id.input_password_login)
var test: String? = null
Login(username.text.toString(), password.text.toString()) {
// Request was successful
if (it.containsKey(true)) {
// Parse return Json
// e.g. {"id":"36e8fac0-487a-11e8-ad4e-c471feb11e42","token":"d6897a230fd7739e601649bf5fd89ea4b93317f6","expiry":"2018-04-27T17:49:48.721278Z"}
val jelement = JsonParser().parse(it.getValue(true))
val jobject = jelement.asJsonObject
// save field for class-scope access
Constants.token = jobject.get("token").asString
Constants.id = jobject.get("id").asString
}
else{
Toast.makeText(this#LoginActivity, it.getValue(false), Toast.LENGTH_SHORT).show()
}
}
test = Constants.id // here test variable surely set if result was successful, otherwise it holds the null value
test?.let{
resultDelivered(it)
}
}[30, TimeUnit.SECONDS]
}
fun resultDelivered(id: String){
// here we know that the async job has successfully finished
}

Categories

Resources