Having issues using v5 API to create a new API key and users

Hello,
Today I started looking at having a java application make API calls into the broker to create new authenticated users and to also create a new API key. With an older version (5.0.8) I believe I was able to create a request from Advanced Rest Client to create a new API key and get a response. I am trying to do the same thing now with 5.0.19 and am constantly asked for authorization.
I have created an API key thru the web interface and used those credentials with no luck. I also tried to create an admin user to pass to the basic authentication with no luck either.

No matter what type of request I try to make into the API I cannot get passed the authentication, I just always receive a response of
{“code”:“BAD_API_KEY_OR_SECRET”,“message”:“Not allowed, Check api_key/api_secret”}

Even using the API-DOCS internal page and “Try It” functionality I cannot get a request to go thru without getting an error back about unauthorized.

Can someone explain what I am doing wrong?

Thank you,
David

Follow up testing.

I went back to my 5.0.8 install and ran the exact same command into the broker to create a new API key using the “admin” user/password for credentials. It worked exactly as expected. Starting the 5.0.19 install back up and running the same command I get the json payload response as mentioned above and in the logs I see the following message.

2023-03-07T10:31:15.448000-05:00 [error] crasher: initial call: cowboy_stream_h:request_process/3, pid: <0.2778.0>, registered_name: [], exit: {{{request_error,{header,<<“authorization”>>},‘Malformed header. Please consult the relevant specification.’},[{base64,decode_binary,5,[{file,“base64.erl”},{line,386}]},{cow_http_hd,parse_authorization,1,[{file,“cow_http_hd.erl”},{line,894}]},{cowboy_req,parse_header,3,[{file,“cowboy_req.erl”},{line,417}]},{emqx_dashboard,authorize,1,[{file,“emqx_dashboard.erl”},{line,229}]},{minirest_handler,do_auth,2,[{file,“minirest_handler.erl”},{line,56}]},{minirest_handler,handle,2,[{file,“minirest_handler.erl”},{line,44}]},{minirest_handler,init,2,[{file,“minirest_handler.erl”},{line,27}]},{cowboy_handler,execute,2,[{file,“cowboy_handler.erl”},{line,41}]},{cowboy_stream_h,execute,3,[{file,“cowboy_stream_h.erl”},{line,318}]},{cowboy_stream_h,request_process,3,[{file,“cowboy_stream_h.erl”},{line,302}]},{proc_lib,init_p_do_apply,3,[{file,“proc_lib.erl”},{line,226}]}]},[{base64,decode_binary,5,[{file,“base64.erl”},{line,386}]},{cow_http_hd,parse_authorization,1,[{file,“cow_http_hd.erl”},{line,894}]},{cowboy_req,parse_header,3,[{file,“cowboy_req.erl”},{line,417}]},{emqx_dashboard,authorize,1,[{file,“emqx_dashboard.erl”},{line,229}]},{minirest_handler,do_auth,2,[{file,“minirest_handler.erl”},{line,56}]},{minirest_handler,handle,2,[{file,“minirest_handler.erl”},{line,44}]},{minirest_handler,init,2,[{file,“minirest_handler.erl”},{line,27}]},{cowboy_handler,execute,2,[{file,“cowboy_handler.erl”},{line,41}]},{cowboy_stream_h,execute,3,[{file,“cowboy_stream_h.erl”},{line,318}]},{cowboy_stream_h,request_process,3,[{file,“cowboy_stream_h.erl”},{line,302}]},{proc_lib,init_p_do_apply,3,[{file,“proc_lib.erl”},{line,226}]}]}, ancestors: [<0.2777.0>,<0.2285.0>,<0.2284.0>,ranch_sup,<0.1908.0>], message_queue_len: 0, messages: [], links: [<0.2777.0>], dictionary: [], trap_exit: false, status: running, heap_size: 987, stack_size: 29, reductions: 4878; neighbours:

Hi,

I tried to reproduce this problem in my test setup, but without luck so far. The crash report that you provided looks like the token is not a proper base64 string, which is strange, since I don’t see any recent changes to the token generator.
Do you have this problem in test or production environment? It would be interesting to see the browser network debug log showing the requests towards EMQX. But if it’s production environment, then of course you don’t have to share anything.

One common cause for such errors is related to clustering failure. When there are several EMQX nodes behind the load balancer, and they cannot communicate with each other over distribution ports (for example due to firewall), sometimes users run into situation when the login token is generated on one EMQX node, but the next request is sent to another.
So my question is: what does your setup look like? Is it clustered, is there a front proxy/load balancer, did the EMQX nodes successfully form the cluster (it can be checked using emqx_ctl cluster status CLI command)

Thank you for the reply. I am still currently in development working with MQTT in general. We have not released any code to the field. My setup is running locally on my machine with no clusters set up. The application that I am writing is a Java app that is trying to create users thru the API in the built_in database. It makes a call to the API_KEY first to get an application key if I don’t already have one. After it receives the key, then I am using that key to call into the users API entries to create/delete users from the database.

** Update ** I just did another test with manually creating an API key thru web interface, setting the key info into my application to use, rather than make a call into the broker to create one programmatically and it succeeded in creating my user. Has the ability to create an api key programmatically been removed or changed since 5.0.8?

Here is Wireshark traffic of my application attempting to create a new API key using the admin user credentials with a non-default password. The exact same code works flawlessly on a 5.0.8 server instance that I will also include the wireshark traffic for.
POST /api/v5/api_key HTTP/1.1
Content-Type: application/json
Accept: application/json
Authorization: Basic YWRtaW46TWFuY2hlc3Rlcjc3
Content-Length: 108
Host: localhost:18083
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_281)
Accept-Encoding: gzip,deflate

{“enable”:true,“name”:“Envoy”,“desc”:“This key is used by Envoy to create and delete users from the system”}
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic Realm=“minirest-server”
content-length: 82
content-type: application/json
date: Thu, 09 Mar 2023 22:01:09 GMT
server: Cowboy

{“code”:“BAD_API_KEY_OR_SECRET”,“message”:“Not allowed, Check api_key/api_secret”}

When I run the exact same program with 5.0.8 this is what I get:
POST /api/v5/api_key HTTP/1.1
Content-Type: application/json
Accept: application/json
Authorization: Basic YWRtaW46TWFuY2hlc3Rlcjc3
Content-Length: 108
Host: localhost:18083
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_281)
Accept-Encoding: gzip,deflate

{“enable”:true,“name”:“Envoy”,“desc”:“This key is used by Envoy to create and delete users from the system”}
HTTP/1.1 200 OK
content-length: 279
content-type: application/json
date: Thu, 09 Mar 2023 22:09:53 GMT
server: Cowboy

{“api_key”:“627c35a3b9013c6f”,“api_secret”:“jYWNr76zxJDAijcIhlgezmiGtV9COzFB9AJ722JXWhbhC”,“created_at”:“2023-03-09T17:09:54-05:00”,“desc”:“This key is used by Envoy to create and delete users from the system”,“enable”:true,“expired”:false,“expired_at”:“infinity”,“name”:“Envoy”}

I have the same admin user and password set on both instances of the broker configuration. I can create the API keys thru the web interface on both instances and programmatically only on the 5.0.8 instance and not the 5.0.19 instance. If I create an API directly and try to create a user in the built in database using that API key, it works on .8, but not .19. No matter what I do, I cannot get any API calls into build 19 to authenticate.

Is there something in one of the configuration files that I have failed to enable or set on build 19?

Again, thank you for any assistance you can give.

Hi,

Thanks for the wireshark capture, it helped me to understand the situation better.
Apparently the basic auth has been disabled for this endpoint. PR that disables it: fix: disable basic auth for HTTP API · emqx/emqx@c5f557e · GitHub
Sadly, I don’t know the historical context as of why it was changed.

The new flow for getting the login token works like this:

curl -X 'POST' \
  'http://localhost:18083/api/v5/login' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "username": "admin",
  "password": "public"
}'

You can also check out Swagger spec for login endpoint: http://localhost:18083/api-docs/index.html#/Dashboard/post_login (replace localhost with hostname of EMQX broker)

After getting the topic the rest of the APIs work in my test setup:

curl -v --oauth2-bearer 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Nzg0MDY5MDI5ODIsImlzcyI6IkVNUVgifQ.H4z39LijUnLT0xWjPaK9immoZ5-XvPMMxuaSlaSir74'  -X 'POST'   'http://localhost:18083/api/v5/mqtt/topic_metrics' -H 'accept: */*'   -H 'Content-Type: application/json'   -d '{
  "topic": "testtopic/2"
}'
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 127.0.0.1:18083...
* Connected to localhost (127.0.0.1) port 18083 (#0)
* Server auth using Bearer with user ''
> POST /api/v5/mqtt/topic_metrics HTTP/1.1
> Host: localhost:18083
> Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Nzg0MDY5MDI5ODIsImlzcyI6IkVNUVgifQ.H4z39LijUnLT0xWjPaK9immoZ5-XvPMMxuaSlaSir74
> User-Agent: curl/7.81.0
> accept: */*
> Content-Type: application/json
> Content-Length: 28
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-length: 560
< content-type: application/json
< date: Thu, 09 Mar 2023 23:19:00 GMT
< server: Cowboy
< 
* Connection #0 to host localhost left intact
{"create_time":"2023-03-09T23:19:01+00:00","metrics":{"messages.dropped.count":0,"messages.dropped.rate":0.0,"messages.in.count":0,"messages.in.rate":0.0,"messages.out.count":0,"messages.out.rate":0.0,"messages.qos0.in.count":0,"messages.qos0.in.rate":0.0,"messages.qos0.out.count":0,"messages.qos0.out.rate":0.0,"messages.qos1.in.count":0,"messages.qos1.in.rate":0.0,"messages.qos1.out.count":0,"messages.qos1.out.rate":0.0,"messages.qos2.in.count":0,"messages.qos2.in.rate":0.0,"messages.qos2.out.count":0,"messages.qos2.out.rate":0.0},"topic":"testtopic/2"}

I hope it helps.

Again, thank you for the reply. I was thinking that somewhere along the line the API calls were disabled with using the basic username/password authentication. I will try the login command and see if that helps me out.

I have looked thru the swagger docs, but hadn’t looked at the login command.

I will update probably early next week of my status, as I have to go fight a fire with some customer issues.

Thanks
David

I have looked thru the swagger docs, but hadn’t looked at the login command.

Just to clarify my testing methodology, I used emqx/emqx:5.0.19 docker container, and used swagger schema documentation provided by the container itself.

Update:
I have been able to verify that with 5.0.19, if I call the /api/v5/login method, with my admin dashboard credentials as documented, I receive a bearer token in return. With that token, I am then able to call the /api/v5/api_key method using the bearer authentication to create the API key. This works and returns a new api key and password that I can then use for subsequent calls into the other API methods with basic authentication.

Thank you for your assistance on this, I really do appreciate it. My Java code is now working as expected to be able to login, create a key and then make other API calls.