Gsuite provides access token, but using it causes a 403: forbidden

Ward van Hoof
Mega Guru

Hi,

At my client, we would like ServiceNow to read the groups as they are registered in GSuite. I run into an issue with this integration, as i seem to receive a OAuth token, but when i use it i receive a 403 error

From the google docs, i understand that you should (more or less) "impersonate" a user. However, i'm not sure if this is mandatory when using a Service Account in google. Because google created a service account, i do not have a client secret and client ID, but had to compile a .jks file from a certificate and use a JWT integration.

Any assistance will be greatly appreciated, as currently I think i tried everything i could think off.

Below a description of my configuration.

Using the JWT Provider and Application registry, I registered the credentials our Google team provided. Using these credentials I am able to click on the Rest Message (sys_rest_message) "Get oauth Token" which will show "OAuth token flow completed successfully" in the pop up. When i click on "Test" on the HTTP Method (sys_rest_message_fn), however, I receive this: 

HTTP status: 403
Error message: Method failed: (/admin/directory/v1/groups) with code: 403 - Forbidden username/password combo
Error code: 6
Response:
{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "forbidden",
    "message": "Not Authorized to access this resource/api"
   }
  ],
  "code": 403,
  "message": "Not Authorized to access this resource/api"
 }
}

Some key configurations I have:

Endpoint: https://www.googleapis.com/admin/directory/v1/groups?domain=<CLIENT_DOMAIN>


X.509 Certificate:
Record with a .jks file for authentication

JWT Keys:
Links to the X.509 Certificate: 

OAuth Entity Scope:
Requesting the scope: https://www.googleapis.com/auth/admin.directory.group
NOTE: I verified that google grants the service accounts this scope. I also tried the .readonly version

OAuth Entity Profile:
Linking scope, Oauth Provider, JWT Provider

JWT Provider (blacked out parts is the ServiceAccount email provided by google)
1 Custom claim not pictured (scope: https://www.googleapis.com/auth/admin.directory.group) 

find_real_file.png

Application Registry (OAuth)
I had to empty Client ID & Client Secret using a background script, otherwise i would not receive a token, because they are illegal parameters
Oauth entity profile: links to the OAuth entity profile configured (as described above)

find_real_file.png

 

I also tried to test my configuration with this script to debug:

initiateFlow();

function initiateFlow() {
	gs.print('\nstart....');
	var requestor = 'd244b8f0dbdc0c106380ef905b961911';
	var requestor_context = 'sys_rest_message';
	var oauth_provider_profile = '3e285fd0dbdc4810be87553c689619f1';
	var oauth_provider_id = '';

	var tokenRequest = new  sn_auth.GlideOAuthClientRequest();
	tokenRequest.setParameter('oauth_requestor_context', requestor_context);
	tokenRequest.setParameter('oauth_requestor', requestor);
	tokenRequest.setParameter('oauth_provider_profile', oauth_provider_profile);		
	tokenRequest.setParameter('oauth_provider_id', oauth_provider_id);

	var oauthClient = new sn_auth.GlideOAuthClient();
	var tokenResponse = oauthClient.requestTokenByRequest(null, tokenRequest);
	var errorMsg = tokenResponse.getErrorMessage();

	gs.print('Response code: ' + tokenResponse.getResponseCode() + '\nErrorMessage: ' + errorMsg);

	if (tokenResponse) {
		var token = tokenResponse.getToken();
		if (token) {
			if (token.getAccessToken()) {
				gs.print('\nTOKEN RECEIVED:\n' + token.getAccessToken());
				makeRest(token.getAccessToken())
			}
		}
	}
}


function makeRest(recToken) {
	gs.print('\nMake rest using token');
	var endpoint = 'https://www.googleapis.com/admin/directory/v1/groups?domain=<CLIENT_DOMAIN>';

	var sm = new sn_ws.RESTMessageV2();
	sm.setEndpoint(endpoint);
	sm.setHttpMethod('get');
	sm.setRequestHeader('Authorization', 'Bearer ' + recToken);
	var response = sm.execute();
	gs.print('\n\nREST Response:\nBody:\n' + response.getBody() + '\nstatusCode: ' + response.getStatusCode());
}

Which results in this output

As you can see, it notes that a token is received (line 9-13)
All the way at the bottom, you can see the response is "403: forbidden"

*** Script: 
start....
Ignore oauth entity from request. Use provider from oauth entity profile.
Getting JWTProvider for jwtProviderSysId = 92eb2cf4db9c0c106380ef905b9619eb
Getting JWTProviderConfig for jwtProviderId = 92eb2cf4db9c0c106380ef905b9619eb
Started to generate JWT
Successfully generated JWT
StorageEncrypter: ignoring already encrypted text starting with: }iO:S...
*** Script: Response code: 200
ErrorMessage: null
*** Script: 
TOKEN RECEIVED:
ya29.c.Kl6iB3YTIpdRQYZUEF6YTBd_EGAkhhwnpKel_4qR7FopReqY4Mz0-3Ku-C7BT5AedA0oDiI3ehjOS4HVZ3LgaVvcI-Gs6yZrOhoWTsrFWj16zUlVYZQl_wnWd_wWmDjS
*** Script: 
Make rest using token
*** Start  Background transaction - system, user: system
*** Start  Background transaction - system, user: system
Starting: SMTP Sender 2.015a962b37020200daa9a16043990e68, Trigger Type: Interval, Priority: 25, Upgrade Safe: true, Repeat: 1 Minute
Name: SMTP Sender 2
Job Context: 
#Mon Oct 21 01:44:16 PDT 2019

Script: 

*** Start  Background transaction - system, user: system
*** Start  Background transaction - system, user: system
Starting: events process 1.a0e84303db133300a898f7871d9619ae, Trigger Type: Interval, Priority: 25, Upgrade Safe: true, Repeat: 10 Seconds
Name: events process 1
Job Context: 
#Mon Oct 21 01:45:41 PDT 2019
fcScriptName=javascript\:gs.processDelegatedEvents();

Script: 

Starting: Flow Engine Event Handler.1d160122db0000106380ef905b9619d3, Trigger Type: Repeat, Priority: 100, Upgrade Safe: true, Repeat: 2 Seconds
Name: Flow Engine Event Handler
Job Context: 
#Mon Oct 21 01:45:40 PDT 2019

Script: 

Starting: Flow Engine Event Handler.5d160122db0000106380ef905b9619d5, Trigger Type: Repeat, Priority: 100, Upgrade Safe: true, Repeat: 2 Seconds
Name: Flow Engine Event Handler
Job Context: 
#Mon Oct 21 01:45:40 PDT 2019

Script: 

*** Start  Background transaction - system, user: system
*** Start  Background transaction - system, user: system
Starting: Flow Engine Event Handler.65160122db0000106380ef905b9619d9, Trigger Type: Repeat, Priority: 100, Upgrade Safe: true, Repeat: 2 Seconds
Name: Flow Engine Event Handler
Job Context: 
#Mon Oct 21 01:45:40 PDT 2019

Script: 

Completed: SMTP Sender 2 in 0:00:00.004, next occurrence is 2019-10-21 10:47:01
*** Start  Background transaction - system, user: system
Starting: Flow Engine Event Handler.69160122db0000106380ef905b9619d7, Trigger Type: Repeat, Priority: 100, Upgrade Safe: true, Repeat: 2 Seconds
Name: Flow Engine Event Handler
Job Context: 
#Mon Oct 21 01:45:40 PDT 2019

Script: 

Completed: Flow Engine Event Handler in 0:00:00.005, next occurrence is 2019-10-21 10:45:53
Completed: Flow Engine Event Handler in 0:00:00.006, next occurrence is 2019-10-21 10:45:53
Completed: events process 1 in 0:00:00.009, next occurrence is 2019-10-21 10:46:01
Completed: Flow Engine Event Handler in 0:00:00.006, next occurrence is 2019-10-21 10:45:53
Completed: Flow Engine Event Handler in 0:00:00.006, next occurrence is 2019-10-21 10:45:53
Starting: Layer 2 Connections Creation.aeb1ecca7fa133001952baf8befa91ef, Trigger Type: Interval, Priority: 100, Upgrade Safe: false, Repeat: 10 Seconds
Name: Layer 2 Connections Creation
Job Context: 
#Mon Oct 21 01:45:41 PDT 2019
fcScriptName=in the schedule record

Script: 
GlideEventManager('physical_connections_creation').processDelegatedEvents();
Completed: Layer 2 Connections Creation in 0:00:00.007, next occurrence is 2019-10-21 10:46:01
*** Script: 

REST Response:
Body:
{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "forbidden",
    "message": "Not Authorized to access this resource/api"
   }
  ],
  "code": 403,
  "message": "Not Authorized to access this resource/api"
 }
}

statusCode: 403
*** Script: 3600  null
[0:00:00.596] Total Time


thanks in advance for your time and effort!

 

1 ACCEPTED SOLUTION

Ward van Hoof
Mega Guru

The integration is up and running now. This is my resolution:

1. Ensure the "sub" claim is filled with the email address of the admin

2. if you receive the error "OAuth flow failed. Verify the configurations and try again. Error detail:invalid_scope, Invalid downscoping, scopes should not be specified as a request parameter" re-configure your scopes: 

  • add a custom claim  "scope" to your "JWT Provider" (space separated list of scopes)
  • on the Application Registry record (oauth_entity), add the "Oauth entity scopes" record (same as in claim)
  • make that on the "OAuth entity profile" the related list "OAuth Entity Profile Scopes" is EMPTY

View solution in original post

9 REPLIES 9

Ward van Hoof
Mega Guru

The integration is up and running now. This is my resolution:

1. Ensure the "sub" claim is filled with the email address of the admin

2. if you receive the error "OAuth flow failed. Verify the configurations and try again. Error detail:invalid_scope, Invalid downscoping, scopes should not be specified as a request parameter" re-configure your scopes: 

  • add a custom claim  "scope" to your "JWT Provider" (space separated list of scopes)
  • on the Application Registry record (oauth_entity), add the "Oauth entity scopes" record (same as in claim)
  • make that on the "OAuth entity profile" the related list "OAuth Entity Profile Scopes" is EMPTY

Anders Pr_stega
Tera Expert

Hi Ward

I am in the same struggle as you were, and can't get it fully working.

My start point was this community article that is still active in the comment section because the instructions doesn't setup an application registry like your article does but uses the GlideJWTAPI to provide tokens. 

Since you have got it working and you had the time and motivation to help I imagine many people would benefit from your experiences.

Anders

Hi Anders,

I had a document retracing all my steps. I converted it to a blog post, please find it here:

https://community.servicenow.com/community?id=community_article&sys_id=506d94d01b1ddc1017d162c4bd4bc...

Thank you Ward, that was very helpful!

For my setup to work the "sub" claim had to be be unspecified, but that might relate to how the Service Account is setup, and since I am doing this for a customer I don't have access and haven't setup the Service Account in the first place - only received informations about it.

I will definitely reference your post. You're a rockstar! 🙂

Sincerely,

Anders