AFNetworking and Token from Django JWT - python

I have used AFNetworking and I have connected to Django api before.
Now problem is I am trying about token authentication in Django.
http://getblimp.github.io/django-rest-framework-jwt/
I have tried these in terminal and it is okay.
$ curl -X POST -d "username=admin&password=abc123" http://localhost:8000/api-token-auth/
$ curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/
I can now get token from AFNetworking too. How can I assign that token in my AFNetworking? I am not quite familiar with curl and AFNetworking.
I tried like this in AFNetworking and it is not okay.
self.manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:SERVER_PREFIX]];
NSMutableURLRequest *request = [self.manager.requestSerializer requestWithMethod:method URLString:urlStr parameters:parameters error:&error];
[request setValue:#"Authorization: JWT" forHTTPHeaderField:token];
How shall I do?

I got it now. Based on curl command, I need to write like this.
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:#"token"];
if (token) {
token = [NSString stringWithFormat:#"%# %#", #"JWT", token];
[self.manager.requestSerializer setValue:token forHTTPHeaderField:#"Authorization"];
}

Related

Python OAuth Client Credentials Grant Type Returned 400, [error: unsupported grant] type but Curl Works Fine

I am very new to APIs (still learning) and I encountered a very weird issue with Python requests library when trying to initiate an OAuth Authentication flow with Client Credentials Grant Type.
For some reason, whenever I used my Python script (with the help of requests library) to send the HTTP request to the authentication endpoint, I always get
Response Status Code: 400
Response Body/Data returned: {"error":"unsupported_grant_type"}
However, if I tried using curl command line tool to send the request, I will get a successful response with status code 200 with the access token in the response body like this:
{'access_token': 'some access token',
'expires_in': 'num_of_seconds',
'token_type': 'Bearer'}
As a matter of fact, if I tried sending the request using Curl command line tool WITHIN my Python Script (with subprocess.Popen function), I can get the response with status code 200 and the access token with no problem.
Now, with that said, here's the Python script that I used to send the request to initiate the OAuth authentication flow:
import requests
import os
import base64
clientCredentialEndpoint = "https://base_url/path/token"
client_id = os.environ.get('CLIENT_ID')
client_secret = os.environ.get('CLIENT_SECRET')
# -- Encode the <client_id:client_secret> string to base64 --
auth_value = f'{client_id}:{client_secret}'
auth_value_bytes = auth_value.encode('ascii')
auth_value_b64 = base64.b64encode(auth_value_bytes).decode('ascii')
queryParams ={
'grant_type':'client_credentials',
'scope':'get_listings_data'
}
headers = {
'Authorization':f'Basic {auth_value_b64}',
'Content-Type':'application/x-www-form-urlencoded'
}
# send the post request to Authorisation server
response = requests.post(
clientCredentialEndpoint,
params=queryParams,
headers=headers,
)
print(response.status_code)
print(response.text)
whereas the curl command that I used (and worked) to send the request is:
curl -X POST -u '<client_id>:<client_secret>' \
-H "Content-Type: application/x-www-form-urlencoded" \
-d 'grant_type=client_credentials&scope=get_listings_data' \
'https://base_url/path/token'
Again, like I said, if I execute this curl command inside a Python script, it will successfully return the access token with no issue.
Does anyone know what I did wrong in my Python script which caused my request to always fail?
Thanks in advance!
My goodness me, I just realised that the -d in the curl command does not correspond to query params, it stands for 'data'.
Hence, I just need to change my Python script requests.post() a bit so that it looks like this:
response = requests.post(
clientCredentialEndpoint,
data=queryParams,
headers=headers,
)
Hope this helps others.

How to authorize via token in Python to an API

I´m completly new in Python-programming and I´m trying to get access to a e – scooter rental service and crawl the data oft he scooters. The service provider is Bird and has no official API and is only accessible via an app for Android or iOS. Someone found a way and the requirements for the posts and gets are here documented: https://github.com/ubahnverleih/WoBike/blob/master/Bird.md
My problem is after i authorized myself by the token I can´t create a get-request. The Server says all the time:
{"code":401,"message":"Credentials are required to access this resource"}
This is my code:
import requests
import json
import uuid
target = "https://api-auth.prod.birdapp.com/api/v1/auth/email"
headers = { "User-Agent": "Bird/4.53.0 (co.bird.Ride; build:24; iOS 12.4.1) Alamofire/4.53.0"
,"Platform": "ios",
"App-Version": "4.53.0",
"Content-Type": "application/json",
"Device-Id": str(uuid.uuid4())}
data = {"email": "any#mail.com"}
reply = requests.post(target, data=json.dumps(data), headers=headers)
# at this point u get an email and u need to copy the token in the email
token = {"token":"IGzMtdAkQ3icmSFV0V64yQ"}
url_token = 'https://api-auth.prod.birdapp.com/api/v1/auth/magic-link/use'
# now you are authorized and you can start get-requests
get_headers = {"Authorization" : "IGzMtdAkQ3icmSFV0V64yQ",
"Device-id" : str(uuid.uuid4()),
"App-Version" : "4.41.0",
"Location" : json.dumps({"latitude":37.77249,"longitude":-122.40910,"altitude":500,"accuracy":100,"speed":-1,"heading":-1})}
url_get_birds = "https://api.birdapp.com/bird/nearby?latitude=37.77184&longitude=-122.40910&radius=1000"
print((requests.get(url_get_birds, headers = get_headers)).text)
The last print command gives me the 401 error all the time
I guess i don´t use the token in get_headers as an authorization correct…
Sorry to bother you but I really don´t know how to progress.
Thank you very much
I don't think you're using the correct token. It appears to me that you are using the Magic Link token as your Auth for getting scooter locations. The Magic Link token that is included in your Email can't be used as the token to get locations of scooters, it's used as the token to get hold of your Access Token. The correct token should start with something like ey and a long list of characters.
Try run this to get your actual token:
curl --location --request POST 'https://api-auth.prod.birdapp.com/api/v1/auth/magic-link/use' \
--header 'User-Agent: Bird/4.53.0 (co.bird.Ride; build:24; iOS 12.4.1) Alamofire/4.53.0' \
--header 'Device-Id: <YOUR-UUID>' \
--header 'Platform: ios' \
--header 'App-Version: 4.53.0' \
--header 'Content-Type: application/json' \
--header 'Content-Type: text/plain' \
--data-raw '{"token":"9BntNB548R7KyD42ml4hrJA"}'
This will output 2 kinds of tokens - Access and Refresh. The Access Token is the one that you would use to get locations of scooters. It should be implemented like this: Authorization: Bird <ACCESS-TOKEN>

Django DRF JWT authentication get token - JSON parse error - Expecting value

I have simple Django DRF application setup which I have implemented JWT authentication.
I used the Django REST framework JWT documentation
I am using curl to test the implementation.
I can successfully get a token using the following notation used in the documentation:
$ curl -X POST -d "username=admin&password=password123" http://localhost:8000/api-token-auth/
The token is returned in following format:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNpdHJ1Y3AiLCJleHAiOjE1MTE2NTEyMTQsInVzZXJfaWQiOjEsImVtYWlsIjoiY3VydGlzLnBva3JhbnRAZ21haWwuY29tIn0.F1TSkxe5tQVpddetUdOJDdAPP1XB9Bimb5U3c75oWd0"}
However, when I try using this other variation, I get an error:
$ curl -X POST -H "Content-Type: application/json" -d '{"username":"admin","password":"password123"}' http://localhost:8000/api-token-auth/
The error I get is:
{"detail":"JSON parse error - Expecting value: line 1 column 1 (char 0)"}
I also had the same error when trying to refresh or verify the token:
Refresh:
$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-refresh/
Verify:
$ curl -X POST -H "Content-Type: application/json" -d '{"token":"<EXISTING_TOKEN>"}' http://localhost:8000/api-token-verify/
I was adding the token as follows:
curl -X POST -H "Content-Type: application/json" -d '{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNpdHJ1Y3AiLCJleHAiOjE1MTE2NDg5MjIsInVzZXJfaWQiOjEsImVtYWlsIjoiY3VydGlzLnBva3JhbnRAZ21haWwuY29tIn0.T5h_PSvzvKOZCPTS60x5IUm3DgAsRCRmbMJeGWZk3Tw"}' http://localhost:8800/api-token-refresh/
Am I perhaps adding the token incorrectly? Does it need some other formatting with quotes?
Those requests are sending data in two different ways. The first request sends it as form data (x-www-form-urlencoded) which is what your endpoint is expecting and the second request sends it as application/json.
I'm not sure that the library you're using will handle a json request out of the box so one option would be to create a custom endpoint and use something like the following:
import json
def ParseFormData(self, request):
payload = json.loads(request.body.decode('utf-8'))
// use django auth to authorize request and return token
You can read more about it in this answer here: https://stackoverflow.com/a/29514222/5443056
There's instructions for manually creating auth tokens in your library's documentation. Here's the code:
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
i suggest use json.dumps({key:value})

Can't post to Hipchat by python (Curl works)

I'm trying to post to a hipchat room via Python and the v2 API.
I can post without problems via curl in a shell script:
ROOM_ID=123
AUTH_TOKEN=123456789
MESSAGE="Hello World"
curl -H "Content-Type: application/json" \
-X POST \
-d "{ \"from\": \"GTM\",
\"notify\": \"true\",
\"color\": \"red\",
\"message_format\": \"text\",
\"message\": \"$MESSAGE\"
}" \
https://hipchat.server.domain.com/v2/room/$ROOM_ID/notification?auth_token=$AUTH_TOKEN
However sending a message with the same payload via Python fails. I have used ready-made clients as well as simple requests via various http modules, and examples like this:
https://gist.github.com/bdclark/4bc8ed06643e077fa620 (also of course I searched SO itself and tested examples like this one).
As a basic example I tried e.g. this:
host = 'hipchat.host.domain.com'
room = '123'
message = "Hello World"
headers = {'Content-type: application/json'}
color = "yellow"
format = "text"
notify=False
AUTH_TOKEN="123456789"
url = "https://{0}/v2/room/{1}/notification?auth_token={2}".format(host, room, AUTH_TOKEN)
h = httplib2.Http()
payload = {
'from':'FROM',
'message': message,
'notify': notify,
'message_format': format,
'color': color
}
resp, content = h.request(url,"POST",urllib.urlencode(payload),headers=headers)
httplib2 (and clients based on it) return a responseNotReady error. requests (and clients based on it) return a Connection reset by peer error.
Since Curl sends without problems it's probably not an issue with Hipchat itself. I assume that there might be an problem with my Python installation (this is the default 2.7 on MacOs Sierra). So the question would be, how do I find the underlying cause for the errors.
Any help much appreciated.

django-oauth2-provider: get the token without sending the client_secret

I'm using django-oauth2-provider with rest-framework to provide authentication in my API.
My mobile app is going to connect to my REST API to retrieve some data. No third party apps are going to get involved in the process.
According to this, the grant type required for this use case would be the password grant. Since it's a bad idea to store the secret in the device, I need to access the token without it.
I tried to send a request without the secret:
curl -X POST -d "client_id=MY_CLIENT_ID&grant_type=password&username=user&password=pass" http://localhost:8000/oauth2/access_token/
But the response I get is:
{"error": "invalid_client"}
My question is whether it is possible to do this with django-oauth2-provider, and how to do it.
Set Authorization Grant Type as Resource owner password-based
Put WSGIPassAuthorization On at same place as WSGIScriptAlias
You need to create a client through django admin UI and replace "MY_CLIENT_ID" with the ID.
"Client type" of application should be "public"
Just to combine solutions. This is what worked for me. Follow through on the Getting Started guide. However, on creating the application, provide the following:
Name: A name of your choosing
Client Type: Public
Authorization Grant Type: Resource owner password-based
Then the request should be:
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&username=<username>&password=<password>&client_id=<client_id>" http://localhost:8000/o/token/
or, if JSON,
to settings.py add:
OAUTH2_PROVIDER = {
# expect request body Content Type application/json
'OAUTH2_BACKEND_CLASS': 'oauth2_provider.oauth2_backends.JSONOAuthLibCore'
}
curl -X POST \
http://localhost:8000/o/token/ \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "password",
"client_id": "<client_id>",
"username": "<username>",
"password": "<password>"
}'
You should use password grant type. The following curl command works with django-oauth-toolkit. I believe it should work with any other oauth provider as well.
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'grant_type=password&username=user&password=pass&client_id=client_id' 'http://localhost:8000/o/token/'
Please see the following link for more info: https://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified#password

Categories