Token Based Authentication Not working

I seem to remember screwing with that many months ago, and decided it was simply defective.

Maybe you can find the Python code and stick in a few logging statements to see if the API and web calls are treated differently.

Yeah this is a good suggestion, I will try that and see if there is any difference. Thanks

hi @sanket,
How does your exploration go?

I tried the same RPC requests but always return 404 DoesNotExistError (the user not found).
Also tried the command line also the same, user not found.

I use Administrator key:secret to run the method. And also tried other user (with full permissions) key:secret. All the same 404 error.

Is there any other way to generate token for a user?

I use version 12

Is this a HTTP GET request? Try using POST request.

If your method changes the state of the database, use POST . After a successful POST request, the framework will automatically call frappe.db.commit() to commit the changes to the database.
Read more: REST API

2 Likes

GET and POST are the same.
404 Not Found
DoesNotExistError

What should be filled in the user_name ?
I tried email, name, fullname, username nothing succeeded.

I’ll detail what works for me.

To start with, change the following to suit your current set up and then paste into your Unix command line:

export ERP_HOST="dev.erpnext.host";
export OTHER_USER="youself.yourorg@gmail.com";
export TOKEN="72d03ddb0c9e010:0261aee60ce2190";
export ADMIN_PWD="sEcr3t";


With that done, all the rest of the commands below ought to just work as is, when pasted into the command line.

curl --location --request \
    POST "https://${ERP_HOST}/api/method/frappe.core.doctype.user.user.generate_keys?user=${OTHER_USER}" \
--header "Authorization: token ${TOKEN}";


The key and secret are of the administrator. I always use the UI to get the first token (see note below). However there is another way that I explain below.

The return result is:

{
    "message": {
        "api_secret": "bd18c496424153a"
    }
}

Clearly that is only the secret. To get the key, run:

curl --location \
    "https://${ERP_HOST}/api/resource/User/${OTHER_USER}" \
--header "Authorization: token ${TOKEN}";


The response for that will be:

{
    "data": {
        "name": "${OTHER_USER}",
          

        "api_key": "63e2ac4283fede7",
        "api_secret": "***************",

        "doctype": "User",
        "stuff": "lots of stuff",
        "etc": "blabbity blabbity blaaa"  
    }
}

If you find that overwhelming you can install the wonderful jq utility and run:

curl --silent --location \
   "https://${ERP_HOST}/api/resource/User/${OTHER_USER}" \
   --header "Authorization: token ${TOKEN}" \
   | jq -r '.data.api_key';

Which will get you:

63e2ac4283fede7

Pay attention to the --location switch that means, “Automatically follow HTTP redirects”. It could be the reason for your "File not found: errors.

I’m guessing you would like to obviate the UI entirely. To do that you still have to log in, but there is an alternate way to it:

Here it is:

curl --location --cookie-jar oreo.txt \
     --request POST "https://${ERP_HOST}/api/method/login" \
     --header "Content-Type: application/json" \
     --data-raw "{
         \"usr\": \"Administrator\",
         \"pwd\": \"${ADMIN_PWD}\"
}";


This returns, first a bit of meta information in standard out …

{
    "message": "Logged In",
    "home_page": "/desk",
    "full_name": "Administrator"
}

… and second, a cookie file …


# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_
dev.erpnext.host    FALSE   /   TRUE    1616357367   sid         937415344dd12179acxxxxxxxxxa4fb3ddb446ab7843a529e84d8aaa
dev.erpnext.host    FALSE   /   TRUE             0   system_user yes
dev.erpnext.host    FALSE   /   TRUE             0   full_name   Administrator
dev.erpnext.host    FALSE   /   TRUE             0   user_id     Administrator
dev.erpnext.host    FALSE   /   TRUE             0   user_image  

The only cookie that matters is the first: sid, but there’s no reason not to keep using the file as is. Now, it is merely necessary to include --cookie oreo.txt in all future calls:

curl --cookie oreo.txt \
   --request POST \
   "https://${ERP_HOST}/api/method/frappe.core.doctype.user.user.generate_keys?user=${OTHER_USER}";


{
    "message": {
        "api_secret": "fadde32b362577b"
    }
}
curl --silent --cookie oreo.txt \
    "https://${ERP_HOST}/api/resource/User/${OTHER_USER}" \
    | jq -r '.data.api_key';


63e2ac4283fede7

As an aside, as soon as I have completed the wizard after creating an installation, I log in as Administrator, generate a key/pair, do a few other things, save the pair in a private/files file, and then do a full database backup so that, no matter what happens, I don’t have run that horrible wizard again.

file: dev.erpnext.host/private/files/apiKeys.sh

export KEYS="63e2ac4283fede7:fadde32b362577b";
1 Like

I still can’t get pass this.
Always return html and <title>Not Permitted</title>

Second related question:
What if I don’t have UI access to the site to generate user token for authorization?

What are you using to substitute those three values?

Performing the substitutions as indicated…

export ERP_HOST="dev.erpnext.host";
export OTHER_USER="youself.yourorg@gmail.com";
export TOKEN="72d03ddb0c9e010:0261aee60ce2190";
export ADMIN_PWD="sEcr3t";

… into this line …

curl --location \
 “https://${ERP_HOST}/api/resource/User/${OTHER_USER}” \
     --header “Authorization: token ${TOKEN}”;

… should produce a line like this …

curl --location \
   "https://dev.erpnext.host/api/resource/User/youself.yourorg@gmail.com” \
      --header “Authorization: token 72d03ddb0c9e010:0261aee60ce2190”;

Please execute this line:

echo -e “Server: ${ERP_HOST}. User: ${OTHER_USER}. Token ${TOKEN}”;

If you get …

“Server: dev.erpnext.host. User: youself.yourorg@gmail.com. Token 72d03ddb0c9e010:0261aee60ce2190”

… then your variable substitutions are working correctly.

If you get …

“Server: . User: . Token ”

… then you need to be sure you understand how to do variable substitution for your system.

Are you running a Windows machine?

yes I get this:

“Server: ukm.myserver.id. User: ukm@myserver.id. Token 09287xxxxxxxxxxx:56b39zzzzzzzzzz”

I’m also able to get this:

{ “message”: { “api_secret”: “657a978yyyyyyyyy” } }

I’m on CentOS

So, it’s working! Yes?

No :slight_smile:

I get the Not Permitted when runnning the .../api/resource/... (to get the key)

Looking at the response header:

Server: nginx/1.14.1
Date: Sat, 20 Mar 2021 15:12:15 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Page-Name: message
X-From-Cache: False
Link: </assets/frappe/js/lib/jquery/jquery.min.js>; rel=preload; as=script,</assets/js/frappe-web.min.js>; rel=preload; as=script,</assets/js/bootstrap-4-web.min.js>; rel=preload; as=script,</website_script.js>; rel=preload; as=script,</assets/js/erpnext-web.min.js>; rel=preload; as=script,</assets/css/frappe-web-b4.css>; rel=preload; as=style,</assets/css/erpnext-web.css>; rel=preload; as=style,</assets/css/base_theme_web.min.css>; rel=preload; as=style,</assets/css/base_theme_fonts.min.css>; rel=preload; as=style
Set-Cookie: sid=Guest; Expires=Tue, 23-Mar-2021 20:42:14 GMT; Path=/
Set-Cookie: system_user=yes; Path=/
Set-Cookie: full_name=Guest; Path=/
Set-Cookie: user_id=Guest; Path=/
Set-Cookie: user_image=; Path=/
Content-Encoding: gzip

Does the sid=Guest have to do with this error?

Let me clarify:

export ERP_HOST="dev.erpnext.host"; #--> this is target site?
export OTHER_USER="youself.yourorg@gmail.com"; #--> this is the user in target site created as api user?
export TOKEN="72d03ddb0c9e010:0261aee60ce2190"; #--> this is the token for that other_user (from User>API Access>Generate Keys)?

What I’m doing is using the Administrator token pair $(TOKEN) to get the secret and key for ${OTHER_USER}

You can only “get” keys and secrets. You cannot “set” them.

So:

# Target Site
export ERP_HOST="dev.erpnext.host";
# The user in target site for whom you are getting a token
export OTHER_USER="youself.yourorg@gmail.com"; 
# Token of user who is getting a token for OTHER_USER.
export TOKEN="72d03ddb0c9e010:0261aee60ce2190";

This means that you have successfully obtained a token secret for “ukm@myserver.id”.

Your administrator token is : 09287xxxxxxxxxxx:56b39zzzzzzzzzz

To use the API as ukm@myserver.id you cannot use : 09287xxxxxxxxxxx:56b39zzzzzzzzzz.

The key, 09287xxxxxxxxxxx is only valid for the administrator. No one else.

You must connect a second time with :

curl --location \
    "https://${ERP_HOST}/api/resource/User/${OTHER_USER}" \
--header "Authorization: token ${TOKEN}";

You’ll get :

{
    "data": {
        "name": "${OTHER_USER}",
          

        "api_key": "63e2ac4283fede7",
        "api_secret": "***************",

        "doctype": "User",
        "stuff": "lots of stuff",
        "etc": "blabbity blabbity blaaa"  
    }
}

Search in there for api_key, and put the two together.

Such as :

63e2ac4283fede7:657a978yyyyyyyyy

Sorry… I got confused by the Token.

I know this but I copied the wrong key:secret (I copy and paste some key:secrets to a note and mistakenly get the wrong pair :slight_smile: . The 09287xxx is the key of the Other_User I created from UI. So it tried to get its own secret, hence the Not Permitted.

Thanks for your help.

So? Problem solved?

Yes solved. Thank you for your help.

1 Like

Post or GET both working for me ! :smiley:

Can we login Admin ( https://netzoptz.erpnext.com/api/method/login) using token/api key & secret key?