Swagger/OpenAPI Bearer auth with custom header name - authentication

I'm defining (small parts of) an existing API (Samanage) using OpenAPI to assist with some integration work.
I need to authenticate using Bearer auth, but by sending the token in a header other than Authorize.
The server expects Bearer authentication in a header named X-Samanage-Authorization like this example:
curl -H "X-Samanage-Authorization: Bearer <TokenGoesHere>" -H 'Accept: application/vnd.samanage.v2.1+json' -H 'Content-Type: application/json' -X GET https://api.samanage.com/incidents.json
I'm aware of https://swagger.io/docs/specification/authentication/bearer-authentication/, but it doesn't seem to help me fully.
This (OpenAPI 3)
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
...
security:
- bearerAuth: []
Results in an authentication header named the default (Authorization)
curl -X GET "https://api.samanage.com/incidents/12341234.json" -H "accept: application/json" -H "Authorization: Bearer <TokenGoesHere>"
Which then fails (401).
I feel like I want this:
components:
securitySchemes:
bearerAuth:
type: http
name: X-Samanage-Authorization
in: header
scheme: bearer
But that fails validation in Swagger Editor as I believe a type of http doesn't allow the name component (like a type of apiKey would). I couldn't quite make full sense of the docs here to be honest.
I did read about Specification Extensions but being completely new to OpenAPI, I couldn't find any examples on how to actually implement what I need.
Any insight much appreciated!

type: http is for HTTP authentication as defined by RFC 7235 and the IANA HTTP Authentication Scheme Registry. HTTP authentication, by definition, uses the Authorization header.
To use a custom header name, you need to define it as an API key (type: apiKey):
components:
securitySchemes:
bearerAuth:
type: apiKey
name: X-Samanage-Authorization
in: header
Note that since it's a non-standard Bearer scheme, the clients will need to manually add the "Bearer " prefix to the token value. For example, when you click "Authorize" in Swagger UI, you'll need to enter "Bearer TOKEN" instead of just "TOKEN".

Related

Google Cloud Platform swagger openapi config yaml file isn't properly rejecting requests that don't contain my api key in the header

I have this config file for my Google Cloud Platform API Gateway endpoint:
swagger: '2.0'
info:
title: api-1
description: API Gateway First for Testing
version: 1.0.0
securityDefinitions:
api_key_header:
type: apiKey
name: key
in: header
schemes:
- https
produces:
- application/json
paths:
/endpoint1:
post:
summary: Simple echo service
operationId: echo-1
x-google-backend:
address: https://<CLOUD FUNCTION GEN 2 NAME>-<MORE IDENTIFYING INFO>-uc.a.run.app
security:
- api_key_header: []
responses:
'200':
description: OK
As you can see, I'm trying to require an API key in order for my server to call the API safely. In my opinion, an API key is necessary for security to prevent someone from figuring out my endpoint and spaming the GCP function.
I created an API key to use for this API endpoint (I censored a lot of data for privacy reasons):
I tried to call the endpoint in Postman like this:
curl --location --request POST 'https://<API CALLABLE ENDPOINT>.uc.gateway.dev/endpoint1' \
--header 'X-goog-api-key: <MY API KEY HERE>' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"name": "Test1"
}'
The problem is that the Postman request works... always lol. No matter what incorrect API key I use for the header...
I noticed that there is no place where I'm directly referencing my API key name. I'm not sure where I'd put this. How do I alter this API Gateway to properly reject requests that do not contain the correct API key?
All available formats are specified on this documentation.
When requesting Api Key through the header, you have to match a specific name which is "x-api-key".
So for your openapi file, it gives the following securityDefinitions:
securityDefinitions:
api_key_header:
type: "apiKey"
name: "x-api-key"
in: "header"
And the curl request should have this header then:
--header 'x-api-key: <MY API KEY HERE>'

How to use curl command to make a PUT request with api key and secret as authorisation method?

I want to execute an api call to a Saas platform. When I generate the api keys with my account in the platform then i get 2 things:-
api key id : 631f39f37564not/631f39f475646real/635c1192756key
Secret key : -----BEGIN RSA PRIVATE KEY----- ABCDE1234 -----END RSA PRIVATE KEY-----
I am executing the api with my following bash script
#!/bin/bash
export FIELD=90
HOST=https://example.com
PUT_BODY="{\"value\":\"${FIELD}\",\"valueObjectType\":\"String\"}"
curl -sk -X PUT "${HOST}/api/v3/xyz/endpoint" \
-H 'content-type: application/json' \
-H 'x-requested-with: XMLHttpRequest' \
-H "referer: ${HOST}/" \
-H "Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key" \
-d"${PUT_BODY}" | jq '.'
I get 401 unauthorized error
{
"error": {
"status_code": 401,
"status": "Unauthorized"
}
}
Is -H "Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key" the correct way to specify the apikey or do i need to append secret also in the request?
Edit: I cannot use bearer token, need to use api key only.
I converted your curl to PHP and changed the URL to my test site that response with the request header. Because you did not provide a link to the api documentation, I do not know if the request header is what they want.
I find the output request header is the first step in trouble shooting curl requests.
This is what my test site received:
BODY=
${PUT_BODY}
BODY urlencoded
${PUT_BODY}
Your request headers:
Content-Length: 11
Content-Type: application/json
Accept: */*
Referer: ${HOST}/
X-Requested-With: XMLHttpRequest
What is missing? The authorization not included?
So let's try another way.
When the is a key and secret they are usually posted as post data in a POST request.
Yours is a PUT request? No documentation.
When I tried your
"Authorization: apikey 631f39f37564not/631f39f475646real/635c1192756key"
curl ignored it and it was not in the request header.
Why the application/json content type header?
I would expect
Content-Type: application/x-www-form-urlencoded
And I would expect the key and secret to be posted as post data:
-d 'key=<key>&secret=<secret>'
But no documentation.
If it is supposed to be a PUT then the key and secret would be in the query string following the URL.
${HOST}/api/v3/xyz/endpoint?key=<key?&secret=<secret>"
Your api key does not look good. Again no documentation.
The secret is even not in your request. You say "need to use api key only".
If that is true, why does the secret exist?

Waste Management API - Authorization: Bearer problem

Im reading this documentation:
https://api.wm.com/howtotest/#make-an-api-call
And I want to make this test request in the postman:
curl -i https://apitest.wm.com/v1/helloworld \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhbnlvbmVAYW55LmNvbSIsInN1YiI6Ildhc3RlIG1hbmFnZW1lbnQgIHRlYW0iLCJqdGkiOiIwQkQyRTVDQkM2RDE2Mzc0RkNFQSIsInNjb3BlIjpbInNlbGYiLCJoZWxsb3dvcmxkIl0sImlhdCI6MTQ5MDg5ODk1NSwiZXhwIjoxNTIyNDM0OTU1fQ.O2k-senypXFZQwW4Ln3mBg60qzOSo-diPQWVfir3m6Q" \
-H "ClientId: 0BD2E5CBC6D16374FCEA" \
-H "Request-Tracking-Id: 12132"
But i recived response like this:
{
"message": "'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhbnlvbmVAYW55LmNvbSIsInN1YiI6Ildhc3RlIG1hbmFnZW1lbnQgIHRlYW0iLCJqdGkiOiIwQkQyRTVDQkM2RDE2Mzc0RkNFQSIsInNjb3BlIjpbInNlbGYiLCJoZWxsb3dvcmxkIl0sImlhdCI6MTQ5MDg5ODk1NSwiZXhwIjoxNTIyNDM0OTU1fQ.O2k-senypXFZQwW4Ln3mBg60qzOSo-diPQWVfir3m6Q' not a valid key=value pair (missing equal-sign) in Authorization header: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhbnlvbmVAYW55LmNvbSIsInN1YiI6Ildhc3RlIG1hbmFnZW1lbnQgIHRlYW0iLCJqdGkiOiIwQkQyRTVDQkM2RDE2Mzc0RkNFQSIsInNjb3BlIjpbInNlbGYiLCJoZWxsb3dvcmxkIl0sImlhdCI6MTQ5MDg5ODk1NSwiZXhwIjoxNTIyNDM0OTU1fQ.O2k-senypXFZQwW4Ln3mBg60qzOSo-diPQWVfir3m6Q'."
}
This is the example of their official documentation, how it can be it doesnt works, or I didnt do something good?
I think that the error message is potentially misleading. If you are using the test example you need to request a clientid and token from WM per the documentation.
From the documentation:
With a valid access token and clientId, you are ready to make requests to Waste Management API.

What is -u from cURL when adding an authorization header to an http request

I am trying to test one of Mix Panel's API endpoints. I'm using Postman to do this, and in Mix Panel's documentation they use cURL to show you how to make the request. When entering the URL, and the POST data for the request, it works in the sense that it hits the right place, and tells me that I need to be authenticated by adding an authorization header. What I'm confused on is, what should the key be for the header ? in their cURL example its -u API_SECRET, so would the authorization header key be 'username' ?
From documentation
# this uses a test project API secret, replace ce08d087255d5ceec741819a57174ce5
# with your own API secret
curl https://mixpanel.com/api/2.0/jql \
-u ce08d087255d5ceec741819a57174ce5: \
--data-urlencode params='{"from_date":"2016-01-01", "to_date": "2016-01-07"}' \
--data-urlencode script='function main(){ return Events(params).groupBy(["name"], mixpanel.reducer.count()) }'
If I wanted to create an AJAX query for example
$.ajax({
method: 'POST',
url: 'https://mixpanel.com/api/2.0/jql',
data: {
'params': '{"from_date":"2016-01-01", "to_date": "2016-01-07"}',
'script': '\'function main(){ return Events(params).groupBy(["name"], mixpanel.reducer.count()) }\''
},
headers: {
<WHAT GOES HERE>: API_SECRET
}
}).then(function success(response){
console.log('SUCCESS');
console.log(response)
}, function error(response){
console.log('There was an error running JQL');
console.log(response.error)
});
In this case, your API_SECRET is the username and there is no password. So using curl -u <API_SECRET>: without any "username" key is correct.
From the mixpanel documentation on an example call https://mixpanel.com/help/reference/data-export-api
Authorization steps The Data Export API accepts Basic access
authentication over HTTPS as an authorization method. To make an
authorized request, put your project's API Secret in the "username"
field of the Basic access authentication header. Make sure you use
HTTPS and not HTTP - our API rejects requests made over HTTP, since
this sends your API Secret over the internet in plain text.
Examples Here's an example of a properly-authenticated request made
with cURL:
curl https://mixpanel.com/api/2.0/segmentation/ \
-u YOUR_API_SECRET: \
-d from_date="2016-02-11" -d to_date="2016-02-11" -d event="Viewed Page"

What does '--user' mean with curl

I'm working with an API and I have to send a POST request. I know how to set a header (-H) and (-d) is the body, but what is "--user".
If I submit this with Postman, or in a text editor with axios or just regular XMLRequest, where do I add this?
The docs say it is for regular http auth.
curl -X POST -H "Content-Type: application/json" \
--user "<client_id>:<client_secret>" \
-d '{"grant_type": "client_credentials", "scope": "public"}' \
...
Late to the party, but here goes...
You can use curl with the -v (verbose) parameter to see the headers sent. You will then see that the information provided with --user is transformed into a header, such as:
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
The text after the Basic keyword is a base64 encoded text string of the username:password combination provided with the --user parameter
To manually generate the base64 encoded credentials on Linux, you can simply call:
echo -n "username:password" | base64 -w0
For windows, save the "username:password" to a file, then use certutil.exe to create a base64 encoded file:
certutil -encode credentials.txt credentials.asc
To test this end to end, you can remove --user username:password and substitute with --header Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l and it will still authenticate just fine.
In summary, to do this manually without curl, you would need to base64 encode username:password combination. You would then need to set the HTTP Authorization header with the type as Basic along with the base64 encoded string.
--user parameter in curl used for server authentication. So if you don't define authentication type via other parameters like --digest or --negotiate, it means USER parameter for http basic authentication, it also could be combined with :PASSWORD chunk to set a password as well. The full answer on your question depends on what kind authentication is used behind API you are sending request to, and maybe curl would not be enough for it, as it support a limited set of authentication schemes ...
--user (or -u) in curl provides a basic auth to your request.
In Postman you can achieve the same result with a choice in Authorization tab.
--user "<client_id>:<client_secret>" becomes
Type: Basic Auth
Username: client_id
Password: client_secret
Specify the user name and password to use for server authentication. If you simply specify the user name, curl will prompt for a password.
If your curl request does not have any -- user, then
server that requires authentication sends back a 401 response code and an associated WWW-Authenticate: header that lists all the authentication methods that the server supports.
< HTTP/1.1 401
< WWW-Authenticate: Basic realm="oauth2/client"
Then you will know the server is using Basic authentication
You can add --basic to explicitly tell it is Basic authentication
Please refer to HTTP authentication for more information
Sometimes (depending on server implementation) the --user will negotiate a digest authenticated session. The headers for digest users are a one-time use. I believe a request to the server will first fail with a 401, but include a WWW-Authenticate response, including the digest realm, and the nonce secret. With these, a second request can be made with a new header Authorization value.
example:
Authorization: Digest username="LXAIQKBC", realm="MMS Public API", nonce="rE3sYnLXEhVMbh72JyUK7kfLIb+bAbKj", uri="/api/atlas/v1.0/groups", cnonce="YTVhM4YwMDB3ZjZjMTkxbCNiODA1ODnxZDFjOGMyMzE=", nc=00000001, qop=auth, response="7a5fcb8e4f92a665315bf62cdd87a67d", algorithm="MD5"
As an addition to Jahmic's answer, Nodejs programmers can do this to convert to base64 string:
const cryptoJS = require("crypto-js");
const base64Str = cryptoJS.enc.Base64.stringify(cryptoJS.enc.Utf8.parse(`${username}:${password}`))