Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How auth can be added to the request, and reuse the token? #73

Closed
DevGiuDev opened this issue Jul 13, 2024 · 3 comments
Closed

How auth can be added to the request, and reuse the token? #73

DevGiuDev opened this issue Jul 13, 2024 · 3 comments

Comments

@DevGiuDev
Copy link

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.

@armkeh
Copy link

armkeh commented Aug 3, 2024

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'

@armkeh
Copy link

armkeh commented Aug 3, 2024

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

...

@federicotdn
Copy link
Owner

I don't think there's anything to add to this issue, I will leave the following thoughts:

  • The x-www-form-urlencoded encoding 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-Response recently which might make easier the extracting of data from responses received. Otherwise, it is still possible to use Verb-Store + (verb-stored-response ...) to fetch data from previously received responses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants