JWT Request Made but It tells that request does not contain access token - swift

I tried to make a Request with JWT Authorization, The server is Using Python/Flask-Restful. The API Works on Postman, so I guess there must be something wrong with my IOS Code. The server returns an error shows that
"Authorization Required. Request does not contain an access token",
I`m making the request from IOS Using following code.
func GetUserData(username: String, accesstoken: String,completion: #escaping (_ result: UserDataModel) -> Void){
let url = URL(string: "http://********/****/\(****)")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.addValue("Authorization", forHTTPHeaderField: accesstoken)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response as? HTTPURLResponse{
if response.statusCode != 200 {
print("Server Error When Update User Data")
} else {
if let data = data {
do {
******
completion(Data)
}
catch {
print(error)
}
}
}
}
}.resume()
}
I have no idea What is going on, Any help?

It looks like you're adding the header:
Bearer base64junk: Authorization
When instead you want:
Authorization: Bearer base64junk
You just have the parameters to addValue(_:forHTTPHeaderField:) backwards. You want this instead:
request.addValue(accesstoken, forHTTPHeaderField: "Authorization")
This should be obvious if you read that line of code like an English sentence ("value authorization for header field access token"?). In the future, you could also use something like Charles Web proxy to intercept your requests and verify that they are indeed formed the way you expect.

Related

Why response is always {"detail":"Unsupported media type \"text/plain\" in request."} in swift?

I have created a sample app in Django which deletes a question from App. And provides a correct output when consumed using POSTMAN.
class Questions(APIView):
def delete(self,request):
received_id = request.POST["id"]
print(received_id)
place = Question.objects.get(pk=received_id)
place.delete()
questions = Question.objects.all()
seriliazer = QuestionSerializer(questions,many = True)
return Response({'Orgs': seriliazer.data})
However, when I am trying to achieve it from iOS app, it's returning {"detail":"Unsupported media type "text/plain" in request."}
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
let postString = "id=15"
request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Could not really understand where exactly the problem is ?
If the api is expecting Json, the body you are sending is not Json, it’s encoded plain text. If it should be Json you can change the body string into the Json format like:
“{\”id\”:15}”
// you may want to tell it what you’re sending
request.setValue("application/json", forHTTPHeaderField: "Accept-Encoding")
Another thing it could be is the request is missing the Accept-Encoding header which tells the api what you’re sending up where Content-Type is what the api typically sends down.
I’ve experienced header injection when I’ve sent requests through specific gateways that aren’t always right. I’d the header isn’t present, something along the way could try to help you out and add the header. This has caused me problems on the past. I still don’t know exactly where in our stack it was occurring, but adding the header fixed my problem.
You can add the header like:
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
DELETE request's body will be ignored, I could guess from the Is an entity body allowed for an HTTP DELETE request? post. HENCE Better to send the complete URL or in header itself,
so I made the function as below
def delete(self,request):
received_id = request.headers['id']
place = Question.objects.get(pk=received_id)
place.delete()
return HttpResponse("DELETE view is working fine ")
and swift
func deleteQuestion( id: Int){
guard let url = URL(string: "http://127.0.0.1:8000/V1/API/questions/") else {
return
}
var request = URLRequest(url: url)
//let postString = "id=\(id)"
// request.httpBody = postString.data(using: String.Encoding.utf8);
request.httpMethod = "DELETE"
request.setValue("charset=utf-8", forHTTPHeaderField: "Accept-Encoding")
request.setValue("charset=utf-8", forHTTPHeaderField: "Content-Type")
request.setValue("\(id)", forHTTPHeaderField: "id")
URLSession.shared.dataTask(with: request) { data, response, error in
let str = String(decoding: data!, as: UTF8.self)
print(str)
if error == nil {
self.fetcOrganizatinData()
}
}.resume()
}
Shortly add Content-Type application/json in your headers
Reason
this happens because the postman has some default headers usually 8.
One of them is
Content-Type text/plain
and by writing "Content-Type": "application/json" we can overwrite that rule.
So whenever you want to pass your data like JSON do that.
to learn more what is by default in postman
I recommend you to read this official documentation of postman.
It happens with me I solved this with overwriting default Content-Type

sending get / put / post in swift

I can easily issue a GET request and it returns (as expected) JSON data that is decoded to myDataModel object:
class func getData(completionHandler: #escaping (myDataModel?, Error?) -> Void)
{
let url = "https://example.com/api/someResource?ws_key=ABC...XYZ"
if let myUrl = URL(string: url)
{
URLSession.shared.dataTask(with: myUrl)
{
(data, response, err) in
if let data = data
{
do
{
let result = try JSONDecoder().decode(myDataModel.self, from: data)
completionHandler(result, nil)
}
catch let JSONerr
{
completionHandler(nil, JSONerr)
}
}
}.resume()
}
}
This work fine, so GET is no problem. (PS. the above has been simplified and modified.)
Likewise, I can issue a POST request and it returns (as expected) JSON data, when I use parameters like key1=value1&key2=value2. (I read that the default POST Content-Type is application/x-www-form-urlencoded.)
However, in another application I need to POST a piece of XML. After many tries and getting many errors, the approach I'm using is to: Set the header Content-Type to text/xml; charset=utf-8; Have no parameters and send the XML as the request body. I use a refined method:
PostHTTP(url: "https://example.com/api/someResource?ws_key=ABC...XYZ",
parameters: nil,
headers: ["Content-Type": "text/xml; charset=utf-8", "Content-Length": "\(xml.count)"],
body: "\(xml)") { (result) in ... }
(I image that you can determine what happens behind the scenes.)
For the POST request, to send a piece of XML:
Do I need to set the Content-Length or is this automatic?
Can I send parameters with the XML?
What headers (like Content-Type) do I require?
What structure (eg. xml=<?xml...) and encoding (eg. addingPercentEncoding) do I require?
Also I need to PUT data and I have similar method. The response from my attempt has the error
String could not be parsed as XML, XML length: 0
For a PUT request:
What headers (like Content-Type) do I require?
What structure (eg. xml=<?xml...) and encoding (eg. addingPercentEncoding) do I require?
Since I have tried many ways, an example of both PUT and POST would be ideal.
If you want to send data of XML you can do this in both PUT and POST
It does not have to be determined Content-Length
But you must add Content-Type
let req = NSMutableURLRequest(url: URL(string:"myUrl")!)
req.httpMethod = "POST"
req.setValue("application/xml;charset=utf-8;", forHTTPHeaderField: "Content-Type")
req.setValue("application/xml;", forHTTPHeaderField: "Accept")
var postBody = Data()
if let anEncoding = ("<?xml version='1.0' encoding='UTF-8'?>").data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "<Request>".data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "<test>\(123)</test>".data(using: .utf8) {
postBody.append(anEncoding)
}
if let anEncoding = "</Request>".data(using: .utf8) {
postBody.append(anEncoding)
}
req.httpBody = postBody
req.setValue("\(postBody.count)", forHTTPHeaderField: "Content-Length")
URLSession.shared.dataTask(with: req as URLRequest) { (data, urlreq, error) in
}

Swift 3 Oauth2 Imgur Refresh keys - error 400 "Invalid grant_type parameter or parameter missing"

I have an issue when calling the /oauth2/token endpoint of the Imgur API using Swift / NSMutableURLRequest and maybe it's actually just me setting up the request in a wrong way as I don't have a lot of experience with NSMutableURLRequest.
Scenario:
The user has already authenticated my App, he can post photos to his Imgur account.
Problem:
Imgur requires to re-authenticate after 28 days.
That's why after authenticating the App you get a (temporary; for 28 days) access_token and a long-term refresh_token which you use after 28 days to get a new access_token.
I do following API call to retrieve a new access_token but always get the error:
"Invalid grant_type parameter or parameter missing" with error code 400.
Here is my HTTP request:
if let reqUrl = URL(string: "https://api.imgur.com/oauth2/token?refresh_token=\(refreshKey)&client_id=\(CLIENT_ID)&client_secret=\(IMGUR_SECRET)&grant_type=refresh_token")
{
let request = NSMutableURLRequest(url: reqUrl)
print("request: \(reqUrl)")
request.httpMethod = "POST"
request.setValue("Client-ID \(CLIENT_ID)", forHTTPHeaderField: "Authorization")
request.addValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request as URLRequest){ data, response, error in
if (error != nil){
print("error: \(error)")
return
}
print("response: \(response!)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("response string: \(responseString!)")
}
task.resume()
}
refreshKey, CLIENT_ID and IMGUR_SECRET should all be correct.
Thank you in advance for your help!
So, I solved it this way:
let bodyString = "grant_type=refresh_token&client_secret=\(IMGUR_SECRET)&client_id=\(CLIENT_ID)&refresh_token=\(refreshKey)"
request.httpBody = bodyString.data(using: .utf8)
basically setting the parameters in the request's body instead of putting them in the URL.
Hope this can help someone else, too :)

Setting Headers for OAuth Authenticated User (Bearer)

I am experimenting on OAuth2 (on Laravel) & Swift with Alamofire. I successfully got token, however I couldn't set the headers to be able to get authenticate-specific data from Api.
Without Alamofire, I was setting this header and it was working.
func me(handler: (data: NSDictionary?, error: String?) -> Void)
{
let url = NSURL(string: "/me", relativeToURL: self.baseUrl)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"
if let t = self.getAccessToken()
{
request.setValue("Bearer \(t)", forHTTPHeaderField: "Authorization")
}
}
However I didn't get what to do with Alamofire.
Now I can use getAccessToken() to get token as a string, but I got really confused adapting it to Alamofire style.
I tried this but doesn't pass the authentication middleware for a reason:
let token = getAccessToken()
print(token!) // prints
let headers = ["Authorization":"Bearer \(token)"]
Alamofire.request(.GET, userDetailsEndpoint!, headers: headers)...
Still getting error The resource owner or authorization server denied the request

How to convert cURL form login code to Swift

I am trying to login (form) into a website and parse data with Swift and NSURLSession.
I have been using cURL to confirm that this is actually possible, and the following code returns the webpage-body as expected.
curl -c cookie.txt -d "username=karl" -d "password=ivar" https://talkmore.no/talkmore3/servlet/Login
curl -b cookie.txt https://talkmore.no/talkmore3/servlet/SubscriptionUsage
When I am trying to do this in Swift, I fetch the Cookie from the response header, then I try to retrieve the SubscriptionUsage-webpage by passing the cookie along. However I cannot get this to work.
How can I convert this simple curl syntax to Swift-code using NSURLSession?
Edit: What I've got so far.
func login() -> Void {
var session = NSURLSession.sharedSession()
var request = NSMutableURLRequest(URL: NSURL(string: "https://www.talkmore.no/talkmore3/servlet/Login")!)
request.HTTPMethod = "POST"
var params = "username=karl&password=ivar"
request.HTTPBody = params.dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("text/html", forHTTPHeaderField: "Content-Type")
var task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) -> Void in
println("Response: \(response)")
println("Data: \(NSString(data: data, encoding: NSUTF8StringEncoding)))")
let httpResponse = response as NSHTTPURLResponse
var cookie = httpResponse.allHeaderFields["Set-Cookie"] as String
})
task.resume()
All seems good, I receive the response with a header including "Set-Cookie" = "JSESSIONID=D8307BA498EFE061C86636C51B8AC25D; Path=/talkmore3/; Secure; HttpOnly"; And I believe I have to send this cookie with the next request. But I have failed to replicate the cURL behavior.