Reputation: 565
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
Reputation: 116868
You have authorized your application with
Scope(Scopes.DRIVE_APPFOLDER)
User.message.list requires one of the following scopes
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