Golang OAuth client and refresh token - go

I have configured Go with OAuth against Google. I am then using the access token to do requests against gmail api, contacts api, drive api etc etc. These need the string that is the actual access token, as opposed to the object *oauth2.Token.
Everything works while the access token is valid. Once its not valid, I can't access the data. This makes sense as I need to use the refresh token to get a new access token, before doing the queries against the services.
My understanding is the *http.Client that you create from the OAuth token will do the refresh for a new access token if its necessary, automatically.
However what I am not sure about is how to get the latest access token out of the client to then use as part of the GET request against Google APIs to auth the service.
So to summarize:
//generate client
//get accessToken.AccessToken from client
//do HTTP GET request to get a users image from contact api (or something)
//pass as either a GET parameter, or as a header the access token
If the client handles refreshing the token, then I need to use the client to get the access token so its valid.
How do you do that? I've looked into using config.TokenSource(ctx, tok) and then i can call TokenSource on that, but that doesn't need the client and therefore the token is not refreshed as far as I can tell.

The following function in the "golang.org/x/oauth2" package auto-refreshes the token as necessary.
func (*oauth2.Config).Client(ctx context.Context, t *oauth2.Token) *http.Client
https://pkg.go.dev/golang.org/x/oauth2#Config.Client

Related

Configure Keycloak to include an at_hash claim in the id token

I'm currently using Keycloak 9.0.0. When authenticating using the code flow and exchanging this code, I'm receiving an id token without the at_hash claim.
How do I configure Keycloak to include an at_hash claim in the id token?
Background:
I'm using a "classic" server side rendered (SSR) program, a confidential client.
I'm sending requests to my local http api. But I also have an Angular client. The SSR is a Go programm using github.com/coreos/go-oidc.
Rendered pages that require authentication redirect the visitor to keycloak and back via the redirect_uri.
Since the visitor is logged in its id token is present in the session and I also pass the access token. However the id token has no at_hash claim and thus access token validation fails.
I also have a mobile web version of this site, in Angular and it sends a bearer access token once logged in. This app uses the code flow + pcke.
Both should be able to send authenticated requests, but since I'm using pretty much the only oidc client library for Go available, it requires an at_hash claim being present in the id token to be able to verify access tokens. The package currently has no support for the introspection endpoint.
Both id token and access token are returned from the IDP. But neither has an at_hash claim.
According to OIDC at_hash is mandatory only when access token is issued.
Make sure you are using response_type=id_token token and not response_type=id_token.

AWS Cognito: Add custom claim/attribute to JWT access token

My app creates a custom attribute "userType" for each new signed-up user. Now I would like this "userType" claim/attribute to be added to the JWT access token whenever the user signs in or the token gets refreshed.
Is there an option to tell cognito to add my custom claim/attribute to the JWT access token? (Without a pre token generation Lambda)
Custom attributes are not available in Cognito access token. Currently it is not possible to inject additional claims in Access Token using Pre Token Generation Lambda Trigger as well. PreToken Generation Lambda Trigger allows you to customize identity token(Id Token) claims only.
You can use ID token to get the token with custom attributes.
Access tokens are not intended to carry information about the user. They simply allow access to certain defined server resources.
You can pass an ID Token around different components of your client, and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them.
How to retrieve Id token using amazon cognito identity js
cognitoUser.authenticateUser(authenticationDetails,{
onSuccess: function(result) {
var accessToken = result.getIdToken().getJwtToken();
console.log('accessToken is: ' + accessToken);
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
},
});
I have the same problem when I want to create several microservice. There isn't a way I can customize an access token, but only an identity token. However, I use client credentials in the machine-to-machine which needs access token. So, in no way I can customize my token. At last, I decide to add such info(like user type) in the event header. It's not a very secure way compared to customize a token, but there isn't any other easy way to do it right now. Otherwise, I have to rewrite the authorizer in Cognito. Like rewriting a customize authorizer and it's very painful.
I have the same issue with Cognito; exist other tools like "PingFederate"Auth-server of Ping identity and Auth0 Auth-server; I know that the requirement isn't part of the standard, but these applications were my alternatives to fix this issue
The responses suggesting to use the ID Token for authorization in your backend systems are bad security practice. ID Tokens are for determining that the user is in fact logged in and the identity of that user. This is something that should be performed in your frontend. Access Tokens on the other hand are for determining that a request (to your backend) is authorized. ID Tokens do not have the same security controls against spoofing that Access Tokens have (see this blog from Auth0: https://auth0.com/blog/id-token-access-token-what-is-the-difference/).
Instead, I recommend that your backend accept an Access Token as a Bearer token via the Authorization HTTP header. Your backend then calls the corresponding /userinfo endpoint (see: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) on the authorization server that issued the Access Token, passing such said Access Token to that endpoint. This endpoint will return all of the ID Token information and claims, which you can then use to make authorization decisions in your code.

Spring Security OAuth 2: How to use access token in the javascript client

I have three applications: REST API with Resource Server, Authorization Server and javascript client on VueJs that should use REST Api. Problem in using access token that I get after authorization. First I decided to use local storage or cookie for storing access token, but as I read It's not secure. It's recommended to use cookie with httpOnly, but I can't to access from js. Addition token in url params as well not right way. So what I should to do for using my Rest Api? I'm using Authorization Code grant flow.
When you have a Javascript client, the client itself should act as an OAuth2 client.
Meaning, the server is not what gets the token. The client, the javascript application in the browser, will fetch the token from the authorization server.
You achieve this by using a grant type called implicit.
In this grant type, there is no client_secret, but you must have a valid client_id. You will also not receive a refresh token. But you can receive access tokens and id_token (if you have an OIDC server).
Your question hints at you doing a server side grant (authorization_code,password,etc) and then sending that token to the javascript client. This would be incorrect.
For a great description of OAuth2, we have published this video: https://www.youtube.com/watch?v=u4BHKcZ2rxk
Your JavaScript application would do this:
Do I have a valid token? No
Start implicit grant
Receive token from authorization server
Store token in memory var token = ....
Use the token to invoke API endpoints on the server
Repeat step 5 until token is no longer valid
Go back to step 1
Next step for you is to watch the video and learn more about implicit grant type
As you already guessed, going down the road of getting a token on the server and then sending it to a non secure client exposes your applications in ways you probably do not want.

How to keep access token for subsequent requests in website like in mobile app

I am developing a web api which will server mobile app and website, if as user access login service in api, user get validated and return back with access token, this access token will be stored in mobile and this access token will be used in subsequest requests for the resources in the api this is fine, but how can we store this access token in website(web browser) to use it for subsequest requests, shall we use sessions to store this access token, if so what about statelessness, if we store it in cokies it will be security treat right, please help me guys thanks in advance
I suggest you to store the access token in the browser's local storage.
Syntax to add
localStorage.setItem("appToken", token);
*where token is the value returned after successful authentication and appToken is the local variable holding that value.
Syntax to access token variable
var token = localStorage.appToken;
*you can access the same token in different pages so that you can hit APIs from there.
Syntax to remove the token
localStorage.removeItem("appToken");
*it's better to remove the token from appToken variable if you want to logout from the application.

How to exchange Google one-time authorization code for a refresh token without callback (intranet)?

I'm working on a intranet-based application and I want to use Google services. Currently I have successfully implemented Google Authentication with "Sign-In for Websites" using JavaScript client-side authentication. My users can now sign in or sign up with their Google accounts.
Now I want to use Google API to create and share Google Sheets with my users. These documents will be created with a specific Google account and then shared with my users.
This is why I want to use this server-slide flow to get a one-time authorization code and exchange it for a refresh token:
https://developers.google.com/identity/sign-in/web/server-side-flow
This refresh token will be stored in my database allowing me to user Google services on behalf of this offline user.
Using JavaScript library, I was able to get the one-time authorization code that I send to my server with a AJAX request.
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(grantOfflineAccessCallback);
var grantOfflineAccessCallback = function(authResult) {
var auth_code = authResult.code;
// Exchange the one-time authorization code for tokens
$.post(...);
}
On server-side I use Google API PHP Client (v2.0.0-RC6) to acquire an access and refresh token.
$this->client = new Google_Client();
$this->client->setClientId($this->clientId);
$this->client->setClientSecret($this->clientSecret);
$this->client->setAccessType('offline');
$this->client->setApprovalPrompt('force');
$response = $this->client->fetchAccessTokenWithAuthCode($oneTimeCode);
I wasn't able to exchange the authorization code.
Client error: `POST https://www.googleapis.com/oauth2/v4/token` resulted in a `400 Bad Request` response:
{
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
On this page we can read:
On the server, exchange the auth code for access and refresh tokens.
Use the access token to call Google APIs on behalf of the user.
On the JAVA example code:
REDIRECT_URI: // Specify the same redirect URI that you use with your web
// app. If you don't have a web version of your app, you can
// specify an empty string.
Because the application I working on is an intranet application, I tried to specify an empty string for this redirect_uri parameter before calling fetchAccessTokenWithAuthCode() method:
$this->client->setRedirectUri('');
... result in Redirect URI must be absolute.
Can we use this hybrid server-slide flow without callback URL?
Is there any solution to my problem?
Thanks,
Edit:
redirect_uri is where the user will be redirected to after he signed in. This URL must be registered in the Google Project (developers console). So redirect_uri is NOT the callback...!
Problem is now solved with:
$this->client->setRedirectUri('http://same.url.as.in.developers.console/');

Resources