You can see my code below: private accessToken: string | null = null; constructor(private http: HttpClient) { this.initGoogle(); } initGoogle() { google.accounts.id.initialize({ client_id: this.CLIENT_ID, callback: this.handleCredentialResponse.bind(this), scope: 'https://www.googleapis.com/auth/calendar', }); google.accounts.id.prompt(); } handleCredentialResponse(response: any) { console.log(response.credential); const idToken = response.credential; // idToken for exchange this.exchangeToken(idToken).then((token: string) => { this.accessToken = token; console.log('Access Token: ', this.accessToken); }).catch(error => console.error(error)); } exchangeToken(idToken: string): Promise<string> { return new Promise((resolve, reject) => { const tokenUrl = 'https://oauth2.googleapis.com/token'; const params = new URLSearchParams(); // this approach results in an error saying the Oauth client is not found // params.set('grant_type', 'urn:ietfaramsauth:grant-type:jwt-bearer'); // params.set('assertion', idToken); // this approach results in an error saying the auth code is malformed // params.set('grant_type', 'authorization_code'); // params.set('code', idToken); // params.set('client_id', this.CLIENT_ID); // params.set('client_secret', this.CLIENT_SECRET); this.http.post(tokenUrl, params.toString(), { headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded', }) }).subscribe({ next: (response: any) => { console.log("success"); resolve(response.access_token); }, error: (error) => { // the error is thrown here console.error("Token exchange error: ", error.error); reject(error); } }); }); } This whole is in a calendar service. The beginning of the login process goes smoothly, the prompt opens, I click login, I get the IDToken, but then when I reach the exchange method an error is thrown. I want to authorize to create events in a public google calendar. I checked: My client ID and client secret is correct. The OAuth2 client ID is configured for Web Apps. The Google Calendar API is enabled. My client ID has Authorized JavaScript origins and Authorized redirect URIs set to http://localhost:4200. On the OAuth consent screen my account is added as a test account, so I can access the API. I am not past my limit. My Oauth consent screen scopes are set to .../auth/calendar and .../auth/calendar.events. Here are the error responses: Message: Http failure response for [https://oauth2.googleapis.com/token:](https://oauth2.googleapis.com/token: "https://oauth2.googleapis.com/token:") 400 OK: { "error": "invalid_grant", "error_description": "Malformed auth code." } Message: Http failure response for [https://oauth2.googleapis.com/token:](https://oauth2.googleapis.com/token: "https://oauth2.googleapis.com/token:") 401 OK: { "error": "invalid_client", "error_description": "The OAuth client was not found." } Anyone has any idea what the problem might be? Continue reading...