I have a simple "Sign in with Google" app where only internal users of google workspace can sign in. e.g.
<html>
<body>
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id="g_id_onload"
data-client_id="CLIENT_ID"
data-context="signin"
data-ux_mode="popup"
data-callback="handleCredentialResponse">
</div>
<div class="g_id_signin"
data-type="standard"
data-shape="rectangular"
data-theme="outline"
data-text="signin_with"
data-size="large"
data-logo_alignment="left">
</div>
<script>
function handleCredentialResponse(response) {
console.log(response.credential)
const decodedJwt = decodeJwt(response.credential);
console.log(decodedJwt)
console.log("ID: " + decodedJwt.sub);
console.log('Full Name: ' + decodedJwt.name);
console.log('Given Name: ' + decodedJwt.given_name);
console.log('Family Name: ' + decodedJwt.family_name);
console.log("Image URL: " + decodedJwt.picture);
console.log("Email: " + decodedJwt.email);
}
function decodeJwt(token) {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(window.atob(base64));
}
</script>
</body>
</html>
Requirement is to get custom claims in JWT/idToken (based on custom user attributes or groups to support RBAC on API gateway). What's the best way to achieve that?
This is what I have tried.
- I followed this adding-custom-roles-to-jwt-on-login-with-google-identity-platform article and linked
beforeSignInhook to a cloud function that is returning a hard-coded custom claim
const gcipCloudFunctions = require('gcip-cloud-functions');
const authClient = new gcipCloudFunctions.Auth();
exports.beforeSignIn = authClient.functions().beforeSignInHandler((user, context) => {
console.log({
user,
context
});
return {
customClaims: {
"roleCustomClaim": "SomeRole"
}
};
});
This approach doesn't work with gsi (google identity services) client snippet that I shared above. Cloud function isn't executed (verified using logs) Why is that?
- I added "Google" Identity Provider in Identity Platform's provider tab and configured it with same internal web client used in above snippet.
<html>
<body>
<script src="https://www.gstatic.com/firebasejs/8.0/firebase.js"></script>
<script>
var config = // config copied from identity platform's "Application setup details"
firebase.initializeApp(config);
const provider = new firebase.auth.GoogleAuthProvider();
const auth = firebase.auth();
firebase.auth()
.signInWithPopup(provider)
.then((result) => {
console.log(result)
/** @type {firebase.auth.OAuthCredential} */
var credential = result.credential;
const idToken = credential.idToken;
console.log(idToken)
const decodedJwt = decodeJwt(idToken);
console.log(decodedJwt)
// This gives you a Google Access Token. You can use it to access the Google API.
var token = credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log(user)
// ...
}).catch((error) => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
function decodeJwt(token) {
const base64Url = token.split('.')[1];
const base64 = base64Url.replace('-', '+').replace('_', '/');
return JSON.parse(window.atob(base64));
}
</script>
</body>
</html>
Now cloud function is being executed with 200 status on user login but I am still not getting custom claim in jwt/idToken. Any idea what I am doing wrong?
I can see a warning "Note: Blocking functions are only available for use with Identity Platform. They are not supported with Firebase Authentication." on Customizing the authentication flow using blocking functions but this is confusing since Docs and even Application setup details of Google Identity platform points to firebase and is using firebase SDK.
