Google IOT core- http bridge "request is missing required authentication credential " - iot

I'm trying to get started with google IOT core by posting a simple http request from the command line.
I have set up my registry and device in Console, and added the public key. I set up a telemetry topic. I've generated the JWT using a Qt application I found, using the private key. I'm using the procedure specified at https://cloud.google.com/iot/docs/how-tos/http-bridge. My command is:
curl -X POST -H 'authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJzeWx2YW4tam91cm5leS0xOTU4MTUiLCJleHAiOiIxNTIwMzU4NjMyIiwiaWF0IjoiMTUxOTc1MzgzMiJ9.kDkwtWvfAE+AOYT2cObgh8Mux2n1DOuek1KR0YrsFSI=' -H 'content-type: application/json' --data '{"binary_data": "SGVsbG8="}' -H 'cache-control: no-cache' 'https://cloudiotdevice.googleapis.com/v1/projects/sylvan-journey-195815/locations/europe-west1/registries/MyDeviceRegistry/devices/FirstDevice:publishEvent'
When I try to post the command I get error 401 "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential"
I don't know where to look. Is there a problem with my JWT? Is the format of the command wrong? Do I need to add a public key to the registry or just to the devices. How do I find out what's wrong?
Any guidance much appreciated

A few ideas:
(Update) Check the JWT is valid on JWT.io
Regenerate your EC public / private key and register the device again
Note the maximum lifetime of a token is 24 hours.
Make sure that your device was registered with the correct credentials, region, and Cloud project.
Ensure that HTTP is enabled for your registry
How did you register your device? If the device was registered with a certificate that has expired, you could encounter authentication issues.
The following Python code is how I generate JWTs from the commandline for Curl-testing the HTTP endpoint assuming an RSA256 key:
import datetime
import jwt
import requests
algorithm = 'RS256'
cloud_region = 'your-cloud-region'
device_id = 'your-device-id'
private_key_file = 'path/to/rsa_private.pem'
project_id = 'your-project-id'
registry_id = 'your-registry-id'
token = {
# The time the token was issued.
'iat': datetime.datetime.utcnow(),
# Token expiration time.
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
# The audience field should always be set to the GCP project id.
'aud': project_id
}
# Read the private key file.
with open(private_key_file, 'r') as f:
private_key = f.read()
print(jwt.encode(token, private_key,
algorithm=algorithm).decode('ascii'))
The following image shows you the setting in the Cloud Console for enabling HTTP/MQTT that can be found under IoT Core > Registry > Edit Registry. Note that if you disable HTTP, you will not be able to use the HTTP device bridge.

Related

Server Get a refresh token with an access token using WSO2 Identity Server

I am making the following curl call:
curl -k -d "grant_type=client_credentials" -H "Authorization: Basic <Encoded ID & Secret>)" https://MyIDPUrl/token
I get a response of:
{
"access_token":"MyAccessTokenHere",
"scope":"am_application_scope default",
"token_type":"Bearer",
"expires_in":3212
}
It all seems fine, except that I am not getting a refresh token. I tried adding &scope=openid to the url, and that added an id_token to the response, but not a refresh token.
How can I get a refresh token with WSO2?
The specification states that client_credentials grant type does not return a refresh token.
It makes sense because the point of a refresh token is to not bother the user to login again. But with client_credentials, you can just go get another access token.
source
Yes for the client_credentials grant type there is no usage of having a refresh token. But if you want to get a refresh token you can allow getting a refresh token by changing a configuration in the identity.xml (IS_Home/repository/conf/identity) In the following section,
<SupportedGrantType>
<GrantTypeName>client_credentials</GrantTypeName>
<GrantTypeHandlerImplClass>org.wso2.carbon.identity.oauth2.token.handlers.grant.ClientCredentialsGrantHandler</GrantTypeHandlerImplClass>
<IsRefreshTokenAllowed>false</IsRefreshTokenAllowed>
<IdTokenAllowed>false</IdTokenAllowed>
</SupportedGrantType>
if you change the value of the IsRefreshTokenAllowed to true it should return a refresh token. (You need to restart the server after changing the configuration value). By default it is false as there is no user engagement in this grant type refresh token is not useful.
As #Vaccano said, using client_credentials grant type does not return a refresh token.
Instead you can use Password grant type instead, that does return a refresh token:
curl -k -X POST https://localhost:9443/oauth2/token
-d "grant_type=password&username=Username&password=Password"
-H "Authorization: Basic Base64(consumer-key:consumer-secret)"

Generating a JWT for Apple's DeviceCheck API

I'm attempting to use the DeviceCheck API from Apple. I can't seem to craft a request that doesn't fail with a 401 Unable to verify authorization token I've tried a handful of minor variations.
import java.security.KeyFactory
import java.security.spec.PKCS8EncodedKeySpec
import java.util.Base64
import io.jsonwebtoken.{Jwts, SignatureAlgorithm}
val deviceCheckPrivateKey = "<Key in plaintext without the key-guards>"
val privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder.decode(deviceCheckPrivateKey)))
val builder = Jwts
.builder()
.setHeaderParam("kid", "<key-id-from-file>")
.signWith(SignatureAlgorithm.ES256, privateKey)
.claim("iss", "<team-id>")
.claim("iat", System.currentTimeMillis())
println(builder.compact())
I take the output of this scratch file and plug it in here:
curl -i -H "Authorization: Bearer <Output>" -X POST --data-binary #ValidQueryRequest.json https://api.development.devicecheck.apple.com/v1/query_two_bits
as recommended by Apple's documentation.
Is the overall structure of this right? I'm trying to follow this tutorial which implies this structuring:
But this blurb from Apple:
Each request you send to the query and update endpoints must include an authorization header that contains your authentication key. The authentication key must must use the ES256 algorithm and be in the Base 64 URL–encoded JSON web token format. If your token doesn't use this format, you receive a BAD_AUTHENTICATION_TOKEN HTTP error.
Suggests that rather than signing using the key, my request should "contain my authentication key".
According to: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6
val builder = Jwts
.builder()
.setHeaderParam("kid", "<key-id-from-file>")
.signWith(SignatureAlgorithm.ES256, privateKey)
.claim("iss", "<team-id>")
.claim("iat", System.currentTimeMillis()) // <--- Should be seconds, not milliseconds

How should I use webclient for oauth 2.0?

I handled a lot of API from many exchanges.
I want the API to work without user intervention.
Usually, I wrote codes like this
Dim timestamp = getEstimatedServerTimeStamp().ToString
Dim domain = "https://api.kucoin.com"
Dim endpoint = "/api/v1/" + method
Dim stringtosign = timestamp + "GET" + endpoint '1553106384182GET/api/v1/accounts
'Dim secretandpassphrase = _secret1.Split("|"c)
'Dim secret = secretandpassphrase(0) 'a7c38ae4-b6e3-4254-b78c-*******
'Dim passphrase = secretandpassphrase(1) '7Q5eVqOw*******
Dim hasher = New System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(_secret1))
Dim sighashbyte = hasher.ComputeHash(System.Text.Encoding.UTF8.GetBytes(stringtosign))
Dim sighash = System.Convert.ToBase64String(sighashbyte)
Dim url = domain + endpoint 'url https://api.kucoin.com/api/v1/accounts
Dim response = CookieAwareWebClient.downloadString1(url, "", {Tuple.Create("KC-API-SIGN", sighash), Tuple.Create("KC-API-TIMESTAMP", timestamp), Tuple.Create("KC-API-KEY", _apiKey1), Tuple.Create("KC-API-PASSPHRASE", _passphrase1)})
Return response
So I am using the secret and the API key.
However, at Sstex, something is different.
First, they told me to register a client and a redirect URL. What does redirect URL mean?
I tried
going to https://apidocs.stex.com/#/Profile/get_profile_wallets
to try some demo.
It turns out I can see my wallet content without using my API key and secret at all. Instead of API key and secret I authorize here
https://apidocs.stex.com/#/Profile/get_profile_wallets
Then I can see my balances.
So I tried some similar code after looking on the web
I did
If token = "" Then
Dim token1 = CookieAwareWebClient.downloadString1("https://app.stex.com/oauth/authorize?client_id=1**&client_secret=3vmEisPCGekF1JGePkwdSKdf4Q00lJTKmwxh****")
End If
Instead of json I am getting an html.
So I wonder.
What exactly I should do with OAuth? Is it designed for something different than regular API access?
The manual says I should curl things like
curl -X GET "https://api3.stex.com/profile/wallets?sort=DESC&sortBy=BALANCE" -H "accept: application/json" -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjY1NzUyODQwYmMzMmMwNGU0MTExNmRmYjQ0M2I5NWY4NzAzYmVkYWIyNTk0ZWZhMTg3ZjhhMmQxOThiNzM1NGRkNThjZmYzYWJkZWEzZjg5In0.eyJhdWQiOiIxNDIiLCJqdGkiOiI2NTc1Mjg0MGJjMzJjMDRlNDExMTZkZmI0NDNiOTVmODcwM2JlZGFiMjU5NGVmYTE4N2Y4YTJkMTk4YjczNTRkZDU4Y2ZmM2FiZGVhM2Y4OSIsImlhdCI6MTU1MzI4NTc4NiwibmJmIjoxNTUzMjg1Nzg2LCJleHAiOjE1NTMzMjg5ODYsInN1YiI6IjMxOTgwMSIsInNjb3BlcyI6WyJwcm9maWxlIiwicmVwb3J0cyIsInRyYWRlIl19.aRuu1gmUmpcck_rMh9fcQwfDeJezn0tD0v1aSJ7joIhtsIXAdaw0H-SFOXwzo_HevFrcDnWGrZ4s9sTd1_vgRS2or7HyiV54c0ItVym6bOMKnFhGuxWWLubXN9HstjiM9TSghk7FtF5J0XeIDcY4vp25ycBmWM6Dddeyu4ehu3hurG-jUyT9N1C4u5KwqkYazeE1Z6XpCUrH77tAIlecTssPUzDtM6j-dYJOirYLx-E7fTn6H_bpHq_mosiHEy7IGe2uyggx0UIg4YIIX0noATxNfFiqZlXc32u8NywS7bDkFJ8e4s2r6vbL9pZU7Qe81IFrhs2jgUrQyjxe4SKsyolA9SulwF1haqsRGYTN_fNZyNm7u_Nzs2-RWxZw7h5KHT48AI483bHqJS3qfpjNF7FdpEufnn1QuFplumvyATtlEf56RCTfZ11fWjaET_b19P_3KpJw8H3pYSh8f-7MdIJcn68X1ls_9GahKKlX059I2M_6S2XkjwvnETlhiWGIdpttg2rJ1oHsEiNUuYzj7d1MBKGhSMX4y8OpB9hhW6CjgajG-YVk3SU6JWaVBEY_1w49Q6U-KxD4nzMK5I85Cn1C1iDPExuOwuyRRH1XSxsXLQ9tURsLOytlp7LkUNvzxb5lxZ18ho-OkvkWVkS18oSxR5y__WllywD_6_NT64s"
So I should get a bearer token. How do I get it with say, curl?
I want standard web query such as using curl. I want to avoid unfamiliar library like some specialized oauth library.
I am making an app. I am not making a website. Should I even use oauth2?
I read about oauth2 here
https://aaronparecki.com/oauth-2-simplified/#roles
It says that "users" will see some website and they can "authorize".
Look. The user is me. I got the API key, secret, client id, client secret. I don't want "users" to be shown anything. I approve all this stuff.
Stex says that they will abandon their version 2 API and will use version 3API. They said that version 3 API uses Oauth.
Is oauth even suitable for an app that run unattended?

Unable to validate access token signature obtained from Azure AD in order to secure Web API

I am trying to secure my web api (.net core 2.2) with Azure Ad using implicit flow.
I registered my application in Azure AD using the Azure Portal > Azure Active Directoy > App Registrations > New Application Registration:
Name = MyWebApi
Application Type = Web app / API
Sign-on URL = http://localhost:55000
Once this app is created, I opened its Manifest file and changed oauth2AllowImplicitFlow from false to true.
Thats all I did for the app registration in azure portal.
Then I called the following URL manually from my chrome browser to get access_token:
https://login.microsoftonline.com/MY-AD-TENANT-GUID/oauth2/v2.0/authorize?client_id=MY-REGISTERED-APP-GUID&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A55000&scope=openid&response_mode=fragment
the response from calling the above url is:
http://localhost:55000/#access_token=MY-ACCESS-TOKEN&token_type=Bearer&expires_in=3600&scope=profile+openid+email+00000003-0000-0000-c000-000000000000%2fUser.Read&session_state=b2be972a-cfbc-49f1-bfc0-6c93f6c87d02
when I pass MY-ACCESS-TOKEN as Bearer token in Authorization header to my Web API (.net core 2.2) I get the following exception:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey , KeyId: N-lC0n-9DALqwhuHYnHQ63GeCXc'.
I then tried manually verifying the signature:
when I paste MY-ACCESS-TOKEN in https://jwt.io/ the header is:
{
"typ": "JWT",
"nonce": "AQABAAAAAACEfexXxjamQb3OeGQ4Gugvm6YdOT-bkA0IPllKMt06-J8If5AQ075TVCav94X_ZYcEYKaPneqdJcqYry-Z4XjX0eMN_fiJX_8wXe9D2b6eRiAA",
"alg": "RS256",
"x5t": "N-lC0n-9DALqwhuHYnHQ63GeCXc",
"kid": "N-lC0n-9DALqwhuHYnHQ63GeCXc"
}
I then went to this URL to obtain the public key for kid: N-lC0n-9DALqwhuHYnHQ63GeCXc
https://login.microsoftonline.com/common/discovery/keys
I then pasted the following as a public key on jwt.io to validated token signature:
-----BEGIN CERTIFICATE-----
OBTAINED-PUBLIC-KEY-FROM-THE-ABOVE-URL-HERE
-----END CERTIFICATE-----
and I again get Invalid Signature.
I have been to this thread: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609, but I am not sure why does my token header has nonce value or if this is an issue at all in my case or not.
Any ideas what I am doing wrong here?
I tried this on my side, it worked well.
Request url:
https://login.microsoftonline.com/tenant-name/oauth2/v2.0/authorize?client_id=application_id&response_type=token&redirect_uri=https://snv2app.azurewebsites.net&scope=api://f3d966c0-517e-4e13-a5bb-9777a916b1a0/User.read openid&response_mode=fragment
And when I got the access_token, I parsed it in the jwt.io and entered the public key, I got the result:
What is happening here is the token you are receiving is an access_token for the userInfo endpoint. The audience is graph. Tokens for graph have been modified in a special way so that they must be transformed before the signature can be validated. This allows for graph to forward the token downstream (after transforming) and not worry about a forwarding attack to occur.
To validate see if 'aud == graph'.

Access token does not have the openid scope

I am doing sso sample(travelocity.com) example. When I am trying to access user info with oauth access token using this command,
curl -k -H "Authorization: Bearer b68ba941c9da3d2644d8a63154d28"
https://localhost:9443/oauth2/userinfo?schema=openid
I am getting follwing error
{"error":"insufficient_scope","error_description":"Access token does
not have the openid scope"}
please help, thank you
When you make the first request to the authorization endpoint, you have to include openid in the scope request parameter. OpenID Connect Core 1.0, 3.1.2.1. Authentication Request says as follows.
scope
REQUIRED. OpenID Connect requests MUST contain the openid scope value. If the openid scope value is not present, the behavior is entirely unspecified. Other scope values MAY be present. Scope values used that are not understood by an implementation SHOULD be ignored. See Sections 5.4 and 11 for additional scope values defined by this specification.
For those who tried to put scope in request param and it does not works, put it in the request body in POST /token request
curl --location --request POST 'http://keycloak.local.webapp/realms/WordSpreads/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=word-spreads-web' \
--data-urlencode 'username=bob' \
--data-urlencode 'password=king' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'scope=openid'
I think the change happen keycloak-1902-released
By default the travelocity.com sso sample web app doesn't sent the openid scope in it's access token request. That is the cause for the error you have encountered.
In order to send the openid scope along with the access token request in the travelocity sample you can try the following,
Open travelocity.properties[1] file in the sample web app (You can find it in travelocity.com/WEB-INF/classe)
Uncomment and edit the QueryParams property in the file[1] as shown below
QueryParams=scope=openid
Save the properties file and redeploy the web app and try the access token generated on the userinfo endpoint now :)
[1] https://github.com/wso2/product-is/blob/master/modules/samples/sso/sso-agent-sample/src/main/resources/travelocity.properties
Update
Looks like the setting the scope in QueryParams isn't working,
There's a workaround
Can you change OAuth2.TokenURL in travelocity.propeties as below and try out? I tested this locally and should work.
#OAuth2 token endpoint URL
OAuth2.TokenURL=https://localhost:9443/oauth2/token?scope=openid

Resources