Vatsal Dholakiya
Vatsal Dholakiya

Reputation: 565

Gmail Api Request had insufficient authentication scopes

I am trying to read emails using Gmail API but I have facing Insufficient Permission problem.

Note: I have set Scopes to read Emails.

ManiFestFile.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hatsoff.glogin">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.GLogin">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

I have created GoogleSignInOptions to get emailAddress or User Dynamically.

  //assign googleAuth
    googleAuth = new GoogleAuth();
    // request for google email
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
            .requestIdToken(getString(R.string.server_client_id))
            .requestServerAuthCode(getString(R.string.server_client_id))
            .requestEmail()
            .build();
    // google_signing object to store gso.
    mGoogleSignInClient = GoogleSignIn.getClient(getApplicationContext(), gso);

This someActivityResultLauncher called when user select GoogleAccount from gsoGoogleSignInOptions Dialog.

        //google Dialog click event
    someActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == RESULT_OK) {
                        System.out.println("ActivityResult: " + result.getResultCode());
                        Intent data = result.getData();
                        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
                        authCode = googleAuth.handleSignInResult(task);
                        if (authCode != null) {
                            // Signed in successfully
                            // save AuthCode to sharedPref
                        }
                    } else {
                        System.out.println("ActivityResult: " + result.getResultCode());
                    }
                }
            });

To get AccessToken I am using GoogleTokenResponse.

ReadEmail class

    public class ReadMails extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... strings) {
        SharedPreferences AuthCodePre = getSharedPreferences("oAuth", MODE_PRIVATE);
        if (!AuthCodePre.getString("Auth", "").equals("")) {
            try {
                String MailBody = "";
                // Load client secrets.
                AssetManager am = getAssets();
                InputStream in = am.open("credentials.json");
                if (in == null) {
                    throw new FileNotFoundException("Resource not found: " + in);
                }
                GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
                final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
                GoogleTokenResponse tokenResponse =
                        new GoogleAuthorizationCodeTokenRequest(
                                HTTP_TRANSPORT,
                                JSON_FACTORY,
                                "https://oauth2.googleapis.com/token",
                                clientSecrets.getDetails().getClientId(),
                                clientSecrets.getDetails().getClientSecret(),
                                AuthCodePre.getString("Auth", ""),
                                "http://localhost")
                                .setScopes(Arrays.asList(SCOPES))
                                .execute();

                String accessToken = tokenResponse.getAccessToken();
                // Use access token to call API
                Credential credential = new GoogleCredential.Builder().setTransport(new com.google.api.client.http.javanet.NetHttpTransport())
                        .setJsonFactory(JSON_FACTORY)
                        .setClientSecrets(clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret())
                        .build()
                        .setAccessToken(accessToken);

                // Build a new authorized API client service.
                Gmail service = new Gmail.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
                        .setApplicationName(APPLICATION_NAME)
                        .build();
                //Access gmail inbox
                Gmail.Users.Messages.List RequestList = service.users().messages().list(user).setQ("from:[email protected]");
                ListMessagesResponse listMessagesResponse = RequestList.setMaxResults(100L).execute();
                RequestList.setPageToken(listMessagesResponse.getNextPageToken());

                //Get id of search email
                for (int i = 0; i < listMessagesResponse.getMessages().size(); i++) {
                    String SEmailID = listMessagesResponse.getMessages().get(i).getId();
                    com.google.api.services.gmail.model.Message message = service.users().messages().get(user, SEmailID).execute();
                    //read email body
                    MessagePart msgpart = message.getPayload();
                    List<MessagePart> bodyParts = new ArrayList<>();
                    bodyParts.add(msgpart);
                    for (int j = 0; j < bodyParts.size(); j++) {
                        MailBody = StringUtils.newStringUtf8(Base64.decodeBase64(bodyParts.get(j).getBody().getData()));
                    }
                    System.out.println("EmailBody:==> " + MailBody);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            //signIn
            someActivityResultLauncher.launch(mGoogleSignInClient.getSignInIntent());
        }
        return null;
    }
}

GoogleAuth.java

    public class GoogleAuth {
    public String handleSignInResult(Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            System.out.println("ServerAuthCode: " + account.getServerAuthCode());
            return account.getServerAuthCode();
        } catch (ApiException e) {
            System.out.println("getStatusCode: " + e);
            return null;
        }
    }
}

ErrorLog

W/System.err: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Insufficient Permission",
 W/System.err:     "reason" : "insufficientPermissions"
  } ],
  "message" : "Request had insufficient authentication scopes.",
  "status" : "PERMISSION_DENIED"
}

Error at this Line: ListMessagesResponse listMessagesResponse = RequestList.setMaxResults(100L).execute();

Upvotes: 2

Views: 2502

Answers (1)

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 116868

You have authorized your application with

Scope(Scopes.DRIVE_APPFOLDER)

User.message.list requires one of the following scopes

enter image description here

Change the scope to an appropriate scope and have your user reauthorize your application. The consent screen needs to display the new scope when the user runs the application.

Upvotes: 3

Related Questions