How To Invoke Cloud Functions With Workspace Users?
I am trying to invoke GCP functions through my angular app hosted on App Engine. I cannot seem to find any straightforward answer given my users are not signed up through GCP but through Google Workspace. So in short the app I am building is only for internal users. As of right now I am able to log in fine using Google Authentication, the problem is that after I log in, the cloud function is rejecting my request. I have included all the steps that I've taken along with the error I am receiving from the cloud function.
So heres what I've done so far.
-
I implemented the login button inside of my Angular app using angularx-social-login.
-
I then obtained an OAuth 2.0 Client ID from the GCP project in which the functions are hosted (as this is the same project anyway).
-
After this I registered the OAuth consent screen and set it to internal as I don't want anyone but my internal workspace users to be able to access this
-
I then went to users identity platform and registered the same OAuth 2.0 client ID that I spoke of in step 2.
-
I then set up the GCP function to allow allAuthenticatedUsers (I've tried many other roles but I would accept if I could just get allAuthenticatedUsers to work for now)
-
Finally back in my angular app I passed into the function call headers the idToken that I get each time a user logs in using the Google Login Popup
My code looks like:
DashboardComponent.ts
import {SocialAuthService} from 'angularx-social-login';
...
this.authService.authState.subscribe((user) => {
this.myService.callFunction(user.idToken).subscribe((userRes) => {
...
}
...
FirebaseFunctionService.ts
callFunction(authToken): Observable<any> {
const headers= new HttpHeaders()
.set('content-type', 'application/json')
.set('Access-Control-Allow-Origin', '*')
.set('Authorization', `Bearer ${authToken}`);
return this.http.get('https://my-cloud-function-url/my-function', { headers: headers
});
}
And the response that I get when I call this function is:
error: ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: 'error', …} headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, headers: Map(0)} message: "Http failure response for https://myFunction.cloudfunctions.net/myFunction: 0 Unknown Error" name: "HttpErrorResponse" ok: false status: 0 statusText: "Unknown Error" url: "https://myFunction.cloudfunctions.net/myFunction" [[Prototype]]: HttpResponseBase
Does anyone know why this might be happening? Any help would be greatly appreciated as I am at my wits end. Thanks in advance :)
Status code 0 in the error message indicates a CORS failure. You can go through this GitHub issue comment, where the stackoverflow thread points to a number of reasons for this error.
Also you need to write this line of code in your initialisations :
const cors = require('cors')({origin: true})
and check out Google’s documentation on how to handle CORS requests. Also you have to provide proper permissions - one of the important ones being giving Cloud Functions invoker role to your cloud functions.
Joe, (author of our question) agreed that it was a CORS error but he solved it by giving allUsers
permission (making the function public) and verifying the user in the function itself and the CORS disappeared.
Now the reason behind this :
I think there was some issue with Joe’s authentication mechanism and hence functions were not authenticated. HTTP functions require authentication by default. And as it did not have it, as per documentation the workaround was to make Joe’s function public by setting the --allow-unauthenticated
flag, or use the Console to grant the Cloud Functions Invoker role to allUsers
. Then handle CORS and authentication in the function code (which he was doing as he mentioned).
So when Joe made the function public by granting allUsers and CORS was handled in code, it started working and the CORS errors disappeared.