cowinapi / developer.cowin

This group is created to facilitate technical and integration discussions related to cowin platform. API related contents can be obtained at API setu portal https://apisetu.gov.in/public/marketplace/api/cowin
115 stars 30 forks source link

401 Unauthenticated Access #278

Closed jforjay1 closed 3 years ago

jforjay1 commented 3 years ago

Not able to book appoinment using url "https://cdn-api.co-vin.in/api/v2/appointment/schedule". Response returns 401. Below is the code: (Consider session_list is declared above and has correct value)

urlpost = "https://cdn-api.co-vin.in/api/v2/appointment/schedule"
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'}
for id in range(0,len(session_list)):
    postdata = {"dose": 1,"session_id": str(session_list[id]),"slot": "AFTERENOON","beneficiaries": ["MY SECRET ID"]}
    responsepost = requests.post(urlpost,headers=header,json=postdata)
    postresponsecode = responsepost.status_code
    print(postresponsecode)

Please help me solve this and let me know what I am doing wrong?

gautam404 commented 3 years ago

@jforjay1 you need to pass Bearer Auth (token) in the header and plus have you got the api key?

deepak-ezetap commented 3 years ago

@jforjay1 you need to pass Bearer Auth (token) in the header and plus have you got the api key?

@gautam404 I have got the token after confirming the OTP. I have 2 questions.

  1. How do we get the api key?
  2. How to pass the token in the header? Authorization= OR Authorization=Bearer

Thank you

patelhir commented 3 years ago

@jforjay1 you need to pass Bearer Auth (token) in the header and plus have you got the api key?

How to get API key?

jforjay1 commented 3 years ago

@deepakezetap public key is available on website. if you want private key you need to register for that. public key is 3sjOr2rmM52GzhpMHjDEE1kpQeRxwFDr4YcBEimi

@gautam404 I also wanted to know and of 2nd question😂 and how to use API key?

deepak-ezetap commented 3 years ago

3sjOr2rmM52GzhpMHjDEE1kpQeRxwFDr4YcBEimi

Isn't this the public key for the test server? how do we register to get the key for prod server?

jforjay1 commented 3 years ago

@deepakezetap I guess thats the problem!

@patelhir You have be organization/company to get 'x-api-key' for production server and they do not give it to individual.

Check this out might help you to test but wont give exactly what you want https://github.com/cowinapi/developer.cowin/issues/282#issue-895214687

deepak-ezetap commented 3 years ago

@jforjay1 Do you have any link to get the prod keys? I will register it through the company.

patelhir commented 3 years ago

@deepakezetap I guess thats the problem!

@patelhir You have be organization/company to get 'x-api-key' for production server and they do not give it to individual.

Check this out might help you to test but wont give exactly what you want #282 (comment)

But many people says that you don't need API-key a token is enough to get access protected endpoints?

deepak-ezetap commented 3 years ago

But many people says that you don't need API-key a token is enough to get access protected endpoints?

I am not sure about this. I tried to fetch the beneficiary list using the token through protected api, but got unauthenticated access. Here is my header: Authorization= OR Authorization=Bearer I dont know what I am doing wrong here.

jforjay1 commented 3 years ago

@deepakezetap check https://github.com/cowinapi/developer.cowin/issues/282#issue-895214687 for authorization

You need to login in basically to generate a token. and login is done by Generating OTP. Check process to generate OTP at https://apisetu.gov.in/public/marketplace/api/cowin#/User%20Authentication%20APIs/generateOTP and also need to confirm it https://apisetu.gov.in/public/marketplace/api/cowin#/User%20Authentication%20APIs/confirmOTP now your token is decrypted.

another problem is after 15 min you need to login again as the session expires.

patelhir commented 3 years ago

I have generated token and I get unauthenticated access even if I try with token immediately. Here is my python code:

`import requests import json

user_agent_desktop = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' \ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 ' \ 'Safari/537.36'

url = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"

headers = { 'authorization': "Bearer {token}", 'Accept-Language': 'hi_IN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'User-Agent': user_agent_desktop }

response = requests.get(url, headers=headers)

print(response.text)`

jforjay1 commented 3 years ago

@patelhir Maybe its because API key we need private x-api-key.

jforjay1 commented 3 years ago

Closing this Issue!

Things noted: If you want to book an appointment on Production server need a private key, that is not available to the general public. However, you can use the public key on Test server to try.

kichappa commented 3 years ago

I am not sure about this. I tried to fetch the beneficiary list using the token through protected api, but got unauthenticated access. Here is my header: Authorization= OR Authorization=Bearer I don't know what I am doing wrong here.

@deepakezetap The following [python] code works for me,

URL = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

print(response.json())
deepak-ezetap commented 3 years ago

bearer_token

@kichappa How did you get the bearer_token? Is the same token from OTP confirmation?

kichappa commented 3 years ago

Is the same token from OTP confirmation?

Yes.

patelhir commented 3 years ago

I am not sure about this. I tried to fetch the beneficiary list using the token through protected api, but got unauthenticated access. Here is my header: Authorization= OR Authorization=Bearer I don't know what I am doing wrong here.

@deepakezetap The following [python] code works for me,

URL = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

print(response.json())

EVen this code gives unauthenticated access.

kichappa commented 3 years ago

Even this code gives unauthenticated access.

@patelhir This is the response I got,

{
    'beneficiaries': [{
        'beneficiary_reference_id': 'REDACTED',
        'name': 'REDACTED',
        'birth_year': 'REDACTED',
        'gender': 'REDACTED',
        'mobile_number': 'REDACTED',
        'photo_id_type': 1,
        'photo_id_number': 'REDACTED',
        'comorbidity_ind': 'N',
        'vaccination_status': 'Partially Vaccinated',
        'vaccine': 'COVISHIELD',
        'dose1_date': 'REDACTED',
        'dose2_date': '',
        'appointments': []
    }, {
        'beneficiary_reference_id': 'REDACTED',
        'name': 'REDACTED',
        'birth_year': 'REDACTED',
        'gender': 'REDACTED',
        'mobile_number': 'REDACTED',
        'photo_id_type': 1,
        'photo_id_number': 'REDACTED',
        'comorbidity_ind': '',
        'vaccination_status': 'Partially Vaccinated',
        'vaccine': 'COVISHIELD',
        'dose1_date': 'REDACTED',
        'dose2_date': '',
        'appointments': []
    }, {
        'beneficiary_reference_id': 'REDACTED',
        'name': 'REDACTED',
        'birth_year': 'REDACTED',
        'gender': 'Male',
        'mobile_number': 'REDACTED',
        'photo_id_type': 'Aadhaar Card',
        'photo_id_number': 'REDACTED',
        'comorbidity_ind': 'N',
        'vaccination_status': 'Not Vaccinated',
        'vaccine': '',
        'dose1_date': '',
        'dose2_date': '',
        'appointments': []
    }]
}
patelhir commented 3 years ago

Without passing API key? Can you send your whole python script?

kichappa commented 3 years ago

@patelhir Sure. Forgive me for any redundancy in the code.

First, I generateOTP and validateOTP.

import requests, hashlib, pathlib
# just some random token
secret="U2FsdGVkX1+TPSV7/E3PENx8ObiaQ9mIov/NO0Ry1mt5O8Awl1Ix+kX68wcBDbBTODj4Ejy3KkeW3n8ZqYhlqA=="

URL = "https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP"
response = requests.post(URL, json={
    "mobile": "9876543210",
    "secret": secret
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

otp=str(input("Enter OTP: "))
otpHash=hashlib.sha256(otp.encode()).hexdigest()

URL = "https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp"
response = requests.post(URL, json={
    "otp": otpHash,
    "txnId": response.json()['txnId']
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

# the response has the bearer token
bearer_token=response.json()['token']

Now, I access the list of beneficiaries as so.

URL = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

# printing the beneficiaries list
print(response.json())

Suppose I want the vaccination certificate,

URL = "https://cdn-api.co-vin.in/api/v2/registration/certificate/download?beneficiary_reference_id={}".format(response.json()['beneficiaries'][0]['beneficiary_reference_id'])
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

with pathlib.Path("certificate.pdf") as f:
    f.write_bytes(response.content)

Hope this helps!

gautam404 commented 3 years ago

@kichappa Can You guide us how you got the token no

kichappa commented 3 years ago

@gautam404 As I said in #273, it is just a token that the CoWin - Self Registration Portal generated when I tried to authenticate using OTP.

patelhir commented 3 years ago

@patelhir Sure. Forgive me for any redundancy in the code.

First, I generateOTP and validateOTP.

import requests, hashlib, pathlib
# just some random token
token="U2FsdGVkX1+TPSV7/E3PENx8ObiaQ9mIov/NO0Ry1mt5O8Awl1Ix+kX68wcBDbBTODj4Ejy3KkeW3n8ZqYhlqA=="

URL = "https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP"
response = requests.post(URL, json={
    "mobile": "9876543210",
    "secret": token
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

otp=str(input("Enter OTP: "))
otpHash=hashlib.sha256(otp.encode()).hexdigest()

URL = "https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp"
response = requests.post(URL, json={
    "otp": otpHash,
    "txnId": response.json()['txnId']
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

# the response has the bearer token
bearer_token=response.json()['token']

Now, I access the list of beneficiaries as so.

URL = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

# printing the beneficiaries list
print(response.json())

Suppose I want the vaccination certificate,

URL = "https://cdn-api.co-vin.in/api/v2/registration/certificate/download?beneficiary_reference_id={}".format(response.json()['beneficiaries'][0]['beneficiary_reference_id'])
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

with pathlib.Path("certificate.pdf") as f:
    f.write_bytes(response.content)

Hope this helps!

That works, thank you so much, I was getting error from long.

kichappa commented 3 years ago

@patelhir Happy to help!

rvramesh commented 3 years ago

@kichappa - The token generated is using a AES encryption of a guid and a key both of them seemed to be hardcoded in the .js fil. The guid may denote the version of the application. Need to check if this is changing for every release. For me it was "b5cab167-7977-4df1-8027-a63aa144f04e". This GUID is also getting stored in the jwt token under "secret_key"

kichappa commented 3 years ago

@rvramesh oh okay. Also, I noticed that this secret-key changes for each generateOTP on the portal. Thank you for pointing out that the JWT token stores it too.

Also, do you have an idea of how one can an acceptable secret-key?

rvramesh commented 3 years ago

@kichappa open developer tools and search for the guid i gave. In login module, the secret is set. If you notice it performs AES encryption on the guid and key (both are hardcoded and is not changing). But AES encryption has a mechanism https://stackoverflow.com/a/31836718/30594 where output is different every time when the same text is encrypted.

rvramesh commented 3 years ago

This explains why you could still use the old secret repeatedly.

kichappa commented 3 years ago

@rvramesh This is what I see in their js file.

key: "anonymousLogin",
value: function () {
    return this.http.post(i.a.auth_prefix_url + "/guest/login", {
        user_name: "b5cab167-7977-4df1-8027-a63aa144f04e"
    }, {
        responseType: "text"
    }).pipe(Object(r.a)((function (e) {
        return e
    })))
}

I don't see how/where they are encrypting this. (This is on line 18390 after beautifying the code).

rvramesh commented 3 years ago

@kichappa - Search for the one more occurrence of that guid or for the keyword secret

kichappa commented 3 years ago

@rvramesh thanks for your input. It works.

crackedpotato007 commented 3 years ago

thanks for your input. It works.

were u talking about having a permanent decrypted token from the otp if yes how?

crackedpotato007 commented 3 years ago

@kichappa - The token generated is using a AES encryption of a guid and a key both of them seemed to be hardcoded in the .js fil. The guid may denote the version of the application. Need to check if this is changing for every release. For me it was "b5cab167-7977-4df1-8027-a63aa144f04e". This GUID is also getting stored in the jwt token under "secret_key"

in which file

kichappa commented 3 years ago

Were you talking about having a permanent decrypted token from an OTP?

@arnav7633 No. That was about the secret that is sent in a generateMobileOTP method.

In which file?

The client sided js script that works when the CoWin portal is loaded.

CodeWithBishal commented 3 years ago

@patelhir Sure. Forgive me for any redundancy in the code.

First, I generateOTP and validateOTP.

import requests, hashlib, pathlib
# just some random token
token="U2FsdGVkX1+TPSV7/E3PENx8ObiaQ9mIov/NO0Ry1mt5O8Awl1Ix+kX68wcBDbBTODj4Ejy3KkeW3n8ZqYhlqA=="

URL = "https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP"
response = requests.post(URL, json={
    "mobile": "9876543210",
    "secret": token
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

otp=str(input("Enter OTP: "))
otpHash=hashlib.sha256(otp.encode()).hexdigest()

URL = "https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp"
response = requests.post(URL, json={
    "otp": otpHash,
    "txnId": response.json()['txnId']
}, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    })

# the response has the bearer token
bearer_token=response.json()['token']

Now, I access the list of beneficiaries as so.

URL = "https://cdn-api.co-vin.in/api/v2/appointment/beneficiaries"
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

# printing the beneficiaries list
print(response.json())

Suppose I want the vaccination certificate,

URL = "https://cdn-api.co-vin.in/api/v2/registration/certificate/download?beneficiary_reference_id={}".format(response.json()['beneficiaries'][0]['beneficiary_reference_id'])
response = requests.get(URL, headers={
    "accept": "application/json",
    "Accept-Language": "en_US",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
    "authorization": "Bearer {}".format(bearer_token)
    })

with pathlib.Path("certificate.pdf") as f:
    f.write_bytes(response.content)

Hope this helps!

@kichappa 1) do I have to replace "mobile" with my mobile number? 2) For generating the token for the very first time do I have to use the demo API keys i.e. "3sjOr2.............." 3) How long the same token lasts?

kichappa commented 3 years ago

@CodeWithBishal

Do I have to replace "mobile" with my mobile number?

Yes. Replace the 9876543210 with your mobile number.

2) For generating the token for the very first time, do I have to use the demo API keys i.e. "3sjOr2.............."?

I'm not sure what you're talking about.

3) How long the same token lasts?

A bearer token lasts 3 minutes.

crackedpotato007 commented 3 years ago

Were you talking about having a permanent decrypted token from an OTP?

@arnav7633 No. That was about the secret that is sent in a generateMobileOTP method.

In which file?

The client sided js script that works when the CoWin portal is loaded.

is the 'secret' and the guid responsible for making a token? if yes how can i get this secret cuz in my main it was named 'client_secret'

CodeWithBishal commented 3 years ago

@kichappa "I'm not sure what you're talking about."

In your code there is a secret/token how do I generate this? (just some random token secret="U2FsdGVkX1+TPSV7/E3PENx8ObiaQ9mIov/NO0Ry1mt5O8Awl1Ix+kX68wcBDbBTODj4Ejy3KkeW3n8ZqYhlqA==")

crackedpotato007 commented 3 years ago

@kichappa "I'm not sure what you're talking about."

In your code there is a secret/token how do I generate this? (just some random token secret="U2FsdGVkX1+TPSV7/E3PENx8ObiaQ9mIov/NO0Ry1mt5O8Awl1Ix+kX68wcBDbBTODj4Ejy3KkeW3n8ZqYhlqA==")

thats the bearer received after confirming the otp i suppose

kichappa commented 3 years ago

@CodeWithBishal it is just a secret that you send to authenticate that you "are the CoWin Portal". You can use the same token I've given here.

You may check out #273 or the api.py file in my repo for more information.

@arnav7633 it's not the bearer token.

vishal24tuniki commented 3 years ago

@kichappa I am getting 504 on https://cdn-api.co-vin.in/api/v2/auth/validateMobileOtp in the code you shared. Is it working fine for you?

kichappa commented 3 years ago

@vishal24tuniki try adding these to your request header.

    "origin": "https://selfregistration.cowin.gov.in",
    "referer": "https://selfregistration.cowin.gov.in/"
vishal24tuniki commented 3 years ago

Thanks @kichappa Working now!