How auth can be added to the request, and reuse the token?
Hi,
I'm struggling with this without success. Any sample I see related to verb or restclient use auth. I'm trying to migrate from Insomnia to eMacs with ORG+verb
I'm starting to the login API request. I have to do a POST request to http://localhost:8081/backend/rest/v2/oauth/token
The cUrl command is as follows:
curl --request POST \
--url http://localhost:8081/backend/rest/v2/oauth/token \
--header 'Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data username=admin \
--data password=admin \
--data grant_type=password
And this is what I have
* GetToken :verb:
#+begin_src verb
POST http://localhost:8081/backend/rest/v2/oauth/token
Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy
Content-Type: application/x-www-form-urlencoded
username=admin
password=admin
grant_type=password
#+end_src
But the API always tells me:
{
"error": "invalid_request",
"error_description": "Missing grant type"
}
and I expect to get something like:
{
"access_token": "aYm2RV_bOK5LKEQRcXLqS-_a3_w",
"token_type": "bearer",
"refresh_token": "RoEHzx2MkjKUP91Ew5WJhtFHQZs",
"expires_in": 43199,
"scope": "rest-api"
}
Where I would like to get the access_token to use it in other requests as Bearer.
One thing I do on Insomnia, and I don't know if could be possible here, is that if I call another request, getToken will be called to request a token if necessary.
Thanks.
I don't think it is possible to split the raw data into multiple lines like you have. When I copy that Verb block as curl (C-c C-e C-r c), it gives
curl 'http://localhost:8081/backend/rest/v2/oauth/token' \
-H 'Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-X POST \
--data-raw 'username=admin
password=admin
grant_type=password '
You could join it all on one line using & as delimiters:
* GetToken :verb:
#+begin_src verb
POST http://localhost:8081/backend/rest/v2/oauth/token
Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy
Content-Type: application/x-www-form-urlencoded
username=admin&password=admin&grant_type=password
#+end_src
Or, more readably in my opinion, use an Elisp snippet:
* GetToken :verb:
#+begin_src verb
POST http://localhost:8081/backend/rest/v2/oauth/token
Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy
Content-Type: application/x-www-form-urlencoded
{{(mapconcat 'identity '("username=admin" "password=admin" "grant_type=password") "&")}}
#+end_src
(But the snippet needs to be all on one line; you could probably break it up using a noweb reference if you have a lot more data to include.)
Either of these give a correct looking command when copied to curl:
curl 'http://localhost:8081/backend/rest/v2/oauth/token' \
-H 'Authorization: Basic YXBwYnV5YmFja2VuZC1lcnZEVUdmUjo5YTZhMzUzMjMzZTA4MDgxZDcyMWJjZWM3NDkwOTNhZGU5MTcyZGZkNWM3ZmViYjgxMjc4OWM2ZGRkZmVhMzYy' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-X POST \
--data-raw 'username=admin&password=admin&grant_type=password'
Regarding re-using the token, here is how I've been doing that mostly automatically:
This code block will let us extract elements from the JSON of a response:
#+name: extract-http-response-json
#+begin_src emacs-lisp
;; Search for the JSON contents by looking for a pair of curly braces;
;; if unexpected behaviour occurs, check if the response has extra braces, and if so, this might need to be made smarter
(let ((resp-json (if (string-match "{[^b-a]*}" response) ;; Silly regexp to match all characters including newline (`b-a` is an empty range, so ^-ing it matches all characters)
(match-string 0 response))))
(apply 'verb-json-get resp-json token-path))
#+end_src
Then this code block uses the above to extract the access and refresh tokens specifically:
#+name: extract-auth-tokens
#+begin_src emacs-lisp :var response="" :noweb yes :noweb-prefix no
(verb-var auth-token "") ;; Verb variable must be set before using verb-set-var, so set it to a default "" if not set yet
(let ((token-path '("access_token")))
(verb-set-var "auth-token" <<extract-http-response-json>>))
(verb-var refresh-token "")
(let ((token-path '("refresh_token")))
(verb-set-var "refresh-token" <<extract-http-response-json>>))
;; Echo the raw response for the results block, followed by info on the extracted values
(concat response "\n\n" (format "extracted keycloak-auth-token: %s\nextracted keycloak-refresh-token: %s"
(verb-var auth-token) (verb-var refresh-token)))
#+end_src
Add the below :post header argument to your token request to use the above to extract the tokens:
#+begin_src verb :wrap src ob-verb-response :post extract-auth-tokens(*this*)
POST http://localhost:8081/backend/rest/v2/oauth/token
Content-Type: application/x-www-form-urlencoded
{{(mapconcat 'identity '("username=admin" "password=admin" "grant_type=password") "&")}}
#+end_src
And then you can use the auth token in all your requests by setting it in a top-level heading, and putting all requests that require authentication under that top-level heading:
* My API :verb:
template http://localhost:8081/backend/rest/v2
Authorization: Bearer {{(verb-var auth-token)}}
** Request 1
...
** Request 2
...
I don't think there's anything to add to this issue, I will leave the following thoughts:
- The
x-www-form-urlencodedencoding is just a way of encoding information in the body, and can be achieved using custom Elisp code as @armkeh built in their first comment. I may add a helper function to Verb to make this easier. But otherwise, there is nothing Verb-specific about how this is done. - I have added
Verb-Map-Responserecently which might make easier the extracting of data from responses received. Otherwise, it is still possible to useVerb-Store+(verb-stored-response ...)to fetch data from previously received responses.
Added a helper function for use with x-www-form-urlencoded: https://github.com/federicotdn/verb/commit/ea789bfc05b0e08b670f035c2cd4fc394b5a4f8c