Hey community,
im just testing a basic js api call but im not sure about the correct header.
The code:

beforeSend: function(xhr) {
xhr.setRequestHeader(“Authorization:”,“Token token=mytoken”);
type: “GET”,
url: “https://my_zammad.zammad.com/api/v1/users”,
contentType: “application/json”,
success: function (data) {
error: function(XMLHttpRequest, textStatus, errorThrown) {

I have tried several setRequestHeader versions but the error is always

DOMException: “Invalid header name.”

Im trying to call the zammad test-account(managed, not self hosted). Maybe its a CORS Issue? The CURL call works well.

thx for your help!

Hey that colon on your header key is wrong:
xhr.setRequestHeader(“Authorization:”,“Token token=mytoken”);

xhr.setRequestHeader(“Authorization”,“Token token=mytoken”);

Thank you!
Now im getting the CORS Issue
CORS-Kopfzeile ‘Access-Control-Allow-Origin’ fehlt
CORS-Anschlag schlug fehl

Im not sure, but isn’t that an server-setting?

Yes, you’re right. We prevent cross domain requests for security reasons. Please understand that we won’t change that. It’s in your interest and in the interest of all our customers.

Ok, now i understand…I just have to find another solution now. Thank you for your support!

1 Like

As you’re using a webpage already, maybe going via a PHP script doing the magic makes a workaround for you.

Now i think about using a self-hosted solution: zammad-community (ubuntu/inhouse). Not sure my thoughts are right: to manage the cors issue i have to set the “Access-Control-Allow-Origin” in zammad.conf in /etc/nginx/sites-available or im wrong?

Yes that’s correct, please note that you might need to add certificate stuff (ssl) if you want to use https.
You can copy cat from /opt/zammad/contrib/nginx/zammad_ssl.conf if needed.

OK, i don’t know what went wrong but the CORS problem wont fix. i have tried following:
Added for testing the full CORS rights in zammad.conf

location /ws {
    add_header 'Access-Control-Allow-Origin' '*';
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400;
    proxy_pass http://zammad-websocket;

location / {
    add_header 'Access-Control-Allow-Origin' '*';
    proxy_set_header Host $http_host;
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 300;
    proxy_pass http://zammad-railsserver;

    gzip on;
    gzip_types text/plain text/xml text/css image/svg+xml application/javascript application/x-javascript application/json application/xml;
    gzip_proxied any;

I also tried add_header Access-Control-Allow-Origin *;
and several positions in the file. All leads to a 404 for http://localhost/api/v1/users request.

PS: The curl call works fine but browser throws CORS issue:

curl: (3) Port number ended with ' '
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)

Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, PATCH, OPTIONS
Access-Control-Max-Age: 1728000
Access-Control-Allow-Headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Accept-Language

No one with same issues?

I expanded the zammad.conf with all privileges i found:

add_header ‘Access-Control-Allow-Methods’ ‘GET,OPTIONS,PUT,DELETE’ always;
add_header ‘Access-Control-Allow-Credentials’ ‘true’ always;
add_header ‘Access-Control-Allow-Origin’ ‘$http_origin’ always;
add_header ‘Access-Control-Allow-Headers’ ‘Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With’ always;
add_header ‘Access-Control-Expose-Headers’ ‘Authorization,DNT,User-Agent,Keep-Alive,Content-Type,accept,origin,X-Requested-With,Content-Disposition’ always;

But Firefox degugger says:

Request URL:http://localhost/api/v1/users
Request method:OPTIONS
Remote address:
Status code: 404

Requested header:

OPTIONS /api/v1/users HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization,content-type
Origin: null
Connection: keep-alive
Cache-Control: max-age=0

Firefox Header as curl:

curl ‘http://localhost/api/v1/users’ -X OPTIONS -H ‘User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0’ -H ‘Accept: /’ -H ‘Accept-Language: en-US,en;q=0.5’ --compressed -H ‘Access-Control-Request-Method: GET’ -H ‘Access-Control-Request-Headers: authorization,content-type’ -H ‘Origin: null’ -H ‘Connection: keep-alive’ -H ‘Cache-Control: max-age=0’

No more ideas now…

Is the cause for your problem here.
This is actually not implemented and thus will give you error 404 (not found).

Below you can find all available routes in user context.

                                api_v1_users_search GET|POST|OPTION      /api/v1/users/search(.:format)                                          users#search
                        api_v1_users_password_reset POST                 /api/v1/users/password_reset(.:format)                                  users#password_reset_send
                 api_v1_users_password_reset_verify POST                 /api/v1/users/password_reset_verify(.:format)                           users#password_reset_verify
                       api_v1_users_password_change POST                 /api/v1/users/password_change(.:format)                                 users#password_change
                           api_v1_users_preferences PUT                  /api/v1/users/preferences(.:format)                                     users#preferences
                         api_v1_users_out_of_office PUT                  /api/v1/users/out_of_office(.:format)                                   users#out_of_office
                               api_v1_users_account DELETE               /api/v1/users/account(.:format)                                         users#account_remove
                        api_v1_users_import_example GET                  /api/v1/users/import_example(.:format)                                  users#import_example
                                api_v1_users_import POST                 /api/v1/users/import(.:format)                                          users#import_start
                                api_v1_users_avatar POST                 /api/v1/users/avatar(.:format)                                          users#avatar_new
                                                    GET                  /api/v1/users/avatar(.:format)                                          users#avatar_list
                                                    DELETE               /api/v1/users/avatar(.:format)                                          users#avatar_destroy
                            api_v1_users_avatar_set POST                 /api/v1/users/avatar/set(.:format)                                      users#avatar_set_default
                                    api_v1_users_me GET                  /api/v1/users/me(.:format)                                              users#me
                                       api_v1_users GET                  /api/v1/users(.:format)                                                 users#index
                                                    GET                  /api/v1/users/:id(.:format)                                             users#show
                                                    GET                  /api/v1/users/history/:id(.:format)                                     users#history
                                                    POST                 /api/v1/users(.:format)                                                 users#create
                                 api_v1_update_user PUT                  /api/v1/users/:id(.:format)                                             users#update
                                 api_v1_delete_user DELETE               /api/v1/users/:id(.:format)                                             users#destroy
                                                    GET                  /api/v1/users/image/:hash(.:format)                                     users#image
                          api_v1_users_email_verify POST                 /api/v1/users/email_verify(.:format)                                    users#email_verify
                     api_v1_users_email_verify_send POST                 /api/v1/users/email_verify_send(.:format)                               users#email_verify_send
                                api_v1_user_devices GET                  /api/v1/user_devices(.:format)                                          user_devices#index
                                                    DELETE               /api/v1/user_devices/:id(.:format)                                      user_devices#destroy

1 Like

Thank you very much for that information!
Im not sure if im right but


is part of the pre-flight of an ajax request. this is a part i cant bypass because im sending Authorization in custom header. That’s needed, or im wrong?

Sorry I can’t help you, I can just tell you that there’s nothing listening on “OPTION”-Requests at that end