I'm making a Google Chat bot with NestJS. It accepts slash commands and allows for interaction with an already existing system. The messages returned on the POST endpoint sometimes include private info or JWTs, so I need to improve security.
I need a way to authenticate and reliably identify the user that triggered the bot command. Currently I'm using the user email provided in the POST body and validating the Bearer token from the header.
Is there a good way to authenticate the user and make sure someone didn't just change the email in the request body?
A solution that could work:
Instead of returning the reply message contents in the POST response, send the message directly to the user it was requested for.
So even if someone changes the email in the request body to someone elses, they do not get the reply, only the requested email gets it.
You can verify the authenticity of the app by checking the bearer token send it to the server
POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite
Google Chat includes a bearer token in the Authorization header of every HTTPS Request to an app.
You can verify your bearer token using an open source Google API client library, in your case Node.js
You can review the full guide here
Related
I have implemented a really simple keycloak integration on my maven java web app.
Assuming I am calling a url directly for the keycloak log in page .
http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/auth?client_id=myclientid&response_type=code&scope=openid&redirect_uri=http//localhost:8080/mypage.html
After entering my username & password on success i am being redirected on mypage.html , the url is like this
http://localhost:8080/mypage.html?session_state=c9482da3-50ff-4176-bf3c-54227271c661&code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
If I break this down its
http://localhost:8080/mypage.html?
session_state=c9482da3-50ff-4176-bf3c-54227271c661&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
What would be the simplest - easiest way to get the user currently logged so i can display it's name ?
Looking at the requests you have made you have not completed the OIDC code flow.
I'm assuming that your java application is acting as the OIDC client, in which case it will need to exchange the authorization code for access, id and refresh tokens by calling the token endpoint of your realm.
e.g.
POST /auth/realms/mmyrealm/protocol/openid-connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
A description of the Token Request
The simplest way would be to use a Java OIDC Client or OAuth2 client to do the authorisation and cod exchange for you and provide OAuth2/OIDC token primitives for you to code against.
Have a look at:
Scribe Java OAuth2 client
Nimbus OIDC SDK
The details of the user will be in claims within the tokens returned by the token endpoint, if you are including the user claims in your tokens.
Edit:
The OIDC Authorization code flow is one of the OIDC authorisation flows. It provides the benefit of not exposing any of the actual tokens to the user agent - e.g. web browser - and allows the oidc client to authenticate with the token server before exchanging the code for the OIDC tokens
At a high level the following occurs:
OIDC Client makes an authentication request
Client authenticates - this could be an end user
Authorisation server returns an Authorisation code - on a redirect - to the client
OIDC Client retrieves Access, ID and Refresh Tokens from the authorisation server's token endpoint
If needed User info is retrieved from the UserInfo endpoint or thge access token is inspected using the introspect endpoint
Details of the actual user will be in claims with in the ID token, which is a plain JWT.
Keycloak allows you to embed the claims in the Access token too.
After authentication with Keycloak you will be redirected back to your web applications redirect URI.
As per your breakdown
http://localhost:8080/mypage.html?
session_state=c9482da3-50ff-4176-bf3c-54227271c661&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
Your requst handler will need to extract the code from that request and then make another call to keycloak to exchange the authorisation code for Access, ID and refresh tokens
e.g.
POST /auth/realms/myrealm/protocol/openid-connect/token HTTP/1.1
Host: localhost:8180
ContentType: application/x-www-form-urlencoded
Authorization: <whatever method your oidc client is usingL
grant_type=authorization_code&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b&
client_id=myclientid&
redirect_uri=....
Ideally you have a route handler for accepting the tokens - maybe a tokens enpoint that also accepts query parameters that indicate the original uri requested so that you can redirect back to that if this is a user facing web application.
If it is completely programatic then you can achive all of it using the nimbus sdk.
The has a good summary of the various parts of Authorization Code flow
https://rograce.github.io/openid-connect-documentation/explore_auth_code_flow
I am attempting to get a token via the Cognito API, and failing. I've read through their site, and I'm having a difficult time through their vague examples.
My goal is to have a 3rd part service run monitoring test on an api, which requires it to authenticate and get an identity token and an access token. I am using the yes/no portion of Cognito, which are the User Pools (the simplest of the bunch).
From looking at the documentation, https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-reference.html, I'm not quite understanding the flow.
If I examine the authorize endpoint, it will, using the http GET method, access a UI for an individual to manually enter the information. (doc: https://docs.aws.amazon.com/cognito/latest/developerguide/authorization-endpoint.html)
looking at the token endpoint, it seems like I might be able to do a machine to machine, but it starts to get odd as the documentation, https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html, states I need to get an authentication code, which circles back to the previous paragraph I wrote about the authorize endpoint.
Thanks,
Kelly
Answer is a bit late, but had the same question recently. There is actually some documentation available for this use case, but it´s maybe not complete. So what we are looking for is this:
https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html
To get this working you need - after having setup a User Pool - to add an app client for your server to server connection. In the User Pool go to App clients
and add an app client e.g. "myBackendService1"
You can add multiple app clients per user pool, so maybe you already have another one for your SPA frontend or you want to add multiple for different backend services.
Now the important part in the settings of the app client is, that "Generate Client Secret" is enabled- you can´t change that afterwards!
Next you need to setup your domain where you can get your token from the endpoint described in the aws docs:
Then under "App integration" go to resource servers and add your resource server you want to access (service defined in App Client will be the server who wants to access this resource server after successfull auth)
Also add some scope here, as it will be needed in the api call (e.g. weather.read as shown in the placeholder)
Now you have everything setup to test your endpoint, e.g. in Postman:
Check the Headers carefully and also make sure in Body you set these keys:
For the Authorization Header key make sure to Base64Encode(client_id:client_secret).
And then you should get back a response like this
This token you can now verify in your resource server, as described e.g. here: How to verify JWT from AWS Cognito in the API backend?
or here:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
This applies to hosted UI. I verified and it works.
1) When I auth either google or Cognito with username and password I am redirected to my webpage. Note I use response_type=code and not response_type=token
https://test.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=3e0\j9m&redirect_uri=http://localhost:4200
2) this is the url after the redirect:
http://localhost:4200/?code=66dbcb-4ab1-a3c9-]cb7091
3) Here is curl but simply do this in your js code but you first make a request to get the id_oken, access_token, and the refresh token
curl -H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&client_id=3e0duagpcsh2ga6ddn&redirect_uri=http://localhost:4200" \
-X POST https://test.auth.us-east-1.amazoncognito.com/oauth2/token
4) When the tokes are about to expire you make a call to the below.. you will get new id_token and access_token but not a refresh token.
curl -H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&client_id=3e0duagpcsh2dnne5r8j9m&refresh_token=eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R....
-X POST https://test.auth.us-east-1.amazoncognito.com/oauth2/token
I have discovered that really the only way to do this is to create an API using the AWS Cognito SDK. I've looked at the details of the ETL strategy, and the SDK is the easiest solution.
You can use uber RESTful api to send a reminder, e.g. "Movie at local AMC", to Uber app user. The api document is here.
POST /v1/reminders
But you have to put a token(they call it server token) in http request header for authentication. Doc is here.
curl -H 'Authorization: Token YOUR_SERVER_TOKEN' \
'https://api.uber.com/v1/products?latitude=37.7759792&longitude=-122.41823'
User can use chrome dev tool to see the token. My question is:
Is it secure to put app token in http request header sending from front-end? Why?
Should I call reminder at server or in the browser using Javascript?
While it is possible to remove and generate new server tokens in the Developer Dashboard (screenshot below), you should not make your server token publicly available (e.g. through JS variables in the frontend). With this token, others could create, retrieve, update, and delete reminders.
Furthermore, the server token could be used to retrieve estimates (price & time) and Uber products on your behalf. This may sound insignificant but could impact your application's rate limiting (2000 requests per hour). If the server token is in the wrong hands, it could effectively prevent your application from communicating with the Uber API periodically.
I'd strongly recommend implementing this on the server-side.
I am working on a web app which requires a user to login to their reddit account and according to https://github.com/reddit/reddit/wiki/OAuth2#retrieving-the-access-token I need to send a POST request to https://www.reddit.com/api/v1/access_token with some parameters. I am currently running the server from localhost and I keep getting the error:
XMLHttpRequest cannot load https://www.reddit.com/api/v1/access_token. Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers.
I was struggling with this same issue and figured out that I need to register my app as "Installed" instead of "Web". This will make the authorization redirect with the bearer token instead of the code.
http://wattydev.com/authenticating_a_js-based_reddit_application_with_user_login_%28implicit_grant_flow%29
I am trying to implement OAuth with my javascript client application.
I already have the server up and running.
My workflow is as following:
Open app
Check if token is present
Validate the token
If not present or not valid go to oauth server for the token
Get back to app and repeat 2 and 3
I everything is ok show my app
I am not sure how to implement point 2. I understand that I need to make another call to the server for this but where is the validation endpoint?
I only have /authorize, /user and /logout
Also how should the request be formed? Do I attach token as a GET parameter and thats all?
What if somebody intercepts valid the token?
Depends on your application, but since you have a javascript web application, that most probably can't keep it's credentials secret, you'll need to implement the Implicit Grant as stated in the OAuth 2.0 spec. If however your application CAN keep it's credentials secret, you should implement the Client Credentials Grant (server side application) because it's more secure.
I am not sure how to implement point 2
You should store your access token somewhere in your web application, for instance in localStorage.
The first time a user will access your web application, the user will have NO access token and NO session with your authorization server. Your web application could see if you have an access token by doing something like:
if (!localStorage.getItem('accessToken') {
window.location.replace('https://your-authorization-server/authorize?response_type=token&client_id=<CLIENT_ID>&redirect_uri=<CALLBACK_URL>&scope=<SCOPE>');
}
If there's no access token, you'll need to redirect to your authorization server so that the user can log in with the authorization server. After the user has logged in, the authorization server will redirect the user back to your web application (after the user has granted permission to whatever resource your web application likes to access on behalf of said user) with a valid access token. This access token must be exposed as a hash fragment named access_token, i.e:
https://web-app.com#access_token=123456789X
Now your web application can extract the access token and store it somewhere.
I understand that I need to make another call to the server for this
but where is the validation endpoint? I only have /authorize, /user
and /logout
Your authorization server requires a token validation endpoint. This endpoint will be used by your web application to validate said token (the one you stored somewhere, for instance localStorage). When this endpoint is called with an access token and it turns out the token is valid, the user can continue, otherwise the user will be redirected to the authorization server. If the user already has a session with the authorization server, the user will be redirected back immediately with a new access token, otherwise the user needs to authenticate (login) first.
Also how should the request be formed? Do I attach token as a GET
parameter and thats all?
Some send a GET request with the access token as a url query parameter, others send a POST request with the access token as the payload of the request body.
What if somebody intercepts the valid token?
Always use https and your access token should be valid for a limited amount of time.
Something to keep in mind is that because your application can't keep it's credentials secret, you need to Implement the Implicit Grant, this means you immediately receive the access token when the authorization server authorized the web application based on Client Id and domain. As opposed to Client Credentials Grant where you first receive an Authorization Code that needs to be exchanged for an access token. When using Implicit Grant you can NOT use Refresh Tokens. This means the user NEEDS to go through the entire flow with the authorization server to obtain a new access token. But this isn't really a big deal, because the user will already be logged in with the authorization server, resulting in an immediate redirect, so when implemented correctly in the web application, the user won't notice.
This is just covering it in broad strokes, it really helped me (and I advise you) to read the OAuth 2.0 spec. Hope this helps you out a bit, OAuth is a complex subject!