How can I get a Refresh Token from GCP?
I already got the Client ID and Client Secret from OAuth Client ID, but I can't find any Refresh Token from the credentials?
Google provides a lot of docs around different methods of authentication including refresh tokens but this document is probably most helpful.
Basically, once the user authorises you, in the response you get an authorization code which can be exchanged for an access token and refresh token by making a call to https://oauth2.googleapis.com/token like:
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob%3Aauto&
grant_type=authorization_code
Response:
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
"refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}
Oauth on GCP is covered in depth here.
Related
I'm providing an external-facing REST GET API service in a kubernetes pod on AWS EKS. I had configured an ALB Ingress for this service which enforces Cognito user pool authentication. Cognito is configured with Authorization code grant with the openid OAuth scope enabled.
If I invoke my REST API from the browser, I get redirected to the Cognito login page. After a sucessful authentication on the form here, I can access my REST GET API just fine. This works, but this is not what I'd like to achieve.
Instead of this, I would need to use a Bearer token, after getting successfully authenticated. So first I invoke https://cognito-idp.ap-southeast-1.amazonaws.com using Postman with the request:
"AuthParameters" : {
"USERNAME" : "<email>",
"PASSWORD" : "<mypass>",
"SECRET_HASH" : "<correctly calculated hash>"
},
"AuthFlow" : "USER_PASSWORD_AUTH",
"ClientId" : "<cognito user pool id>"
}
and I get a successful response like:
"AuthenticationResult": {
"AccessToken": "...",
"ExpiresIn": 3600,
"IdToken": "...",
"RefreshToken": "...",
"TokenType": "Bearer"
},
"ChallengeParameters": {}
}
In the last step I'm trying to invoke my REST API service passing the Authorization HTTP header with the value Bearer <AccessToken> but I still get a HTML response with the login page.
How can I configure Cognito to accept my Bearer token for this call as an authenticated identity?
Quoting AWS support on this topic: "the Bearer token can not be used instead of the session cookie because in a flow involving bearer token would lead to generating the session cookie".
So unfortunately this usecase is not possible to implemented as of today.
STANDARD BEHAVIOUR
I would aim for a standard solution, which works like this:
API returns data when it receives a valid access token, or a 401 if the token is missing, invalid or expired - the API never redirects the caller
UIs do their own redirects to the Authorization Server when there is no token yet or when a 401 is received from the API
If it helps, my OAuth Message Workflow blog post demonstrates the 3 legged behaviour between UI, API and Authorization Server.
API GATEWAY PATTERN
It is perfectly fine to use an API Gateway Design Pattern, where token validation is done via middleware before hitting your API.
However that middleware must return a 401 when tokens are rejected rather than redirecting the API client.
IMPACT OF APIs REDIRECTING THE CLIENT
This may just about work for web UIs, though user experience will be limited since the UI will have no opportunity to save the user's data or location before redirecting.
For mobile / desktop apps it is more problematic, since the UI must redirect using the system browser rather than a normal UI view - see the screenshots on my Quick Start Page.
CHOICES
Any of these solutions would be fine:
Possibly the middleware you are using can be configured differently to behave like a proper API Gateway?
Or perhaps you could look for alternative middleware that does token validation, such as an AWS Lambda custom authorizer?
Or do the OAuth work in the API's code, as in this Sample API of mine
MY PREFERENCE
Sometimes I prefer to write code to do the OAuth work, since it can provide better extensibility when dealing with custom claims. My API Authorization blog post has some further info on this.
I am not understanding something about Amazon Cognito. If JWT tokens are only good for an hour, then they need to refresh, but how should my app do this? How does this happen? Do you just request new tokens and it remembers the session you are in? Also, do you store the JWT tokens in the state? I'm not understanding this, if anyone can help out I would appreciate it. Thanks!
When asking for token, if the grant_type is authorization_code the token endpoint returns refresh_token
Sample:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token":"eyJz9sdfsdfsdfsd",
"refresh_token":"dn43ud8uj32nk2je",
"id_token":"dmcxd329ujdmkemkd349r",
"token_type":"Bearer",
"expires_in":3600
}
Then you can exchange the refresh token at the token endpoint to get another token
POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
Content-Type='application/x-www-form-urlencoded'
Authorization=Basic aSdxd892iujendek328uedj
grant_type=refresh_token&
client_id=djc98u3jiedmi283eu928&
refresh_token=REFRESH_TOKEN
Additional documentation can be found here
I am looking to create an API using the Django REST Framework which will authenticate using a separate authentication server by means of its introspection endpoint. The authorization flow should look something like the following.
The client provides either user credentials or a refresh token to the token endpoint on our authentication server.
If the provided credentials or refresh token are valid, the authentication server responds with an access token and a refresh token.
The client then sends the access token to the API when requesting a resource.
The API verifies the provided access token using the introspection endpoint on our authentication server.
The authentication server responds letting the API know if the access token is valid.
If the access token is valid, the API responds to the client with the requested resources.
Step 4 is the part I'm after, and the Django OAuth Toolkit looks like it provides an option for exactly this. In the section about setting up a separate resource server it states that it allows the application to verify access tokens by use of an introspection endpoint.
So I followed the setup for the Django OAuth Toolkit, and pointed the RESOURCE_SERVER_INTROSPECTION_URL toward the introspection endpoint on our authentication server. Then I acquired an access token from our authentication server and provided it to the API as an Authorization header, but I get the following response.
Content-Type: application/json
WWW-Authenticate: Bearer realm="api",error="invalid_token",error_description="The access token is invalid."
Vary: Accept
Allow: GET, HEAD, OPTIONS
Content-Length: 58
{
"detail": "Authentication credentials were not provided."
}
If I don't provide a token I get the same response body, but no WWW-Authenticate header. The strange part is that the introspection endpoint never receives a POST request, which it should be sending to verify the access token.
So did I misread the documentation, or am I doing something wrong? Why isn't this working as I expect?
I used Django Oauth2 toolkit in my django app. my client is an angular web application and uses django api with oauth2.
it perfectly works in my localhost and every thing is ok but when i use application in server after success login and getting the access token when it requests another page with authentication the 401 error occures.
client is client.example.com and django api is on api.example.com.
please help me...
request token:
client_id:ePmICVI9Dwsb0eKCv8aMTKvq4Jnr7ewtFWFZGLEu
grant_type:password
username:mohammad
password:mz575451
client_secret:2RGeORI0eZbKFZX3gYtjGy
response:
{"expires_in": 36000, "token_type": "Bearer", "access_token": "yzKlTXuDLOZj5wGescfkNiejyYKhg2", "scope": "read write", "refresh_token": "JJp5Kxq3PcDQthwvSLxvfW2Ee5rLUE"}
I finally found the solution!!!!!!! ^___^
http://www.django-rest-framework.org/api-guide/authentication/#apache-mod_wsgi-specific-configuration
I have created a backend spring-boot REST api which is deployed on the EC2 that is authenticated with JWT. So, I first curl to get the Bearer token:
curl -iH "Content-Type: application/json" -X POST -d '{"username":"myusername", "password":"mypassword"}' http://123.45.6782.910:8080/login
Then make the REST call to access my REST resource
curl -H "Authorization: eyJhbGzd9.NYHXPv-vXUIoNr7qtA" http://123.45.6782.910:8080/categories/pets/
This all works fine.
Now, I want to use API Gateway to access the /categories/pets/ Resource.
I have setup GET - Method execution's Method request, Integration Request sections. But, when I try to Test the setup, I get 403.
{
"timestamp": 1498392625274,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/categories/pets/"
}
I think this is expected because I am directly trying to access the backend api without the bearer token. I want to know how can I do the POST on http://123.45.6782.910:8080/login to get the Bearer token and then make the call to /categories/pets/ ?
UPDATE: As per #KaHouIeong suggestion, I created a POST endpoint /login on the API gateway to get the bearer token, When I test is in the test console in the API Gateway, I am getting the Authorization →Bearer eyJhbGzd9 but when I try it from postman, I am getting the status 200 OK but not the Authorization →Bearer eyJhbGzd9 token.
content-length →0
content-type →application/json
status →200
via →1.1 swfbfbbaf3fb6c32bdccb152354539e473d.cloudfront.net (CloudFront)
x-amz-cf-id →K9V3XUxHOretrza0kCM5dk_G5eZgePrtrBziyVTxptrePD7wjsWqk-l0kCQQ==
x-amzn-requestid →5ac81024-5c27-11e7-af9a-9f3c8494c542
x-amzn-trace-id →Root=1-5953e77f-ed76d15b5bfre9374c9
Your client should send a request to /login and get the bearer token from the response, then re-use the token to access your /categories/pets/ API.
The workflow should be same as you hit your EC2 backend directly.
For your API setup on API Gateway, you need to setup a /login resource and point to the http://123.45.6782.910:8080/login
Then, you need to setup the integration response header mapping to map the Authorization header back to the method response, then API Gateway will pass through the header to the client.
integration.response.header.Authorization -> method.response.header.Authorization