Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

failing to connect to gmail with imap protocol using oauth2

I am working on creating a program to connect to gmail with imap protocol, using oauth2 mechanism for authentication. I was successfully able to get access token but failing to establish connection. Below are the steps performed and provided code for reference.

1. Created client_id and client_secret
2. Created onetime auth code using (https://accounts.google.com/o/oauth2/auth?client_id=&redirect_uri=http://localhost&response_type=code&scope=https://www.googleapis.com/auth/drive&access_type=offline)
3. Using code got access token and refresh token 
4. Passed access token as oauthToken in the code (session properties)

On google accounts:
Two-factor authentication is enabled
app password is created

 

 

 

 

 

 

public class OAuth2SaslClientFactory implements SaslClientFactory {
  private static final Logger logger =
      Logger.getLogger(OAuth2SaslClientFactory.class.getName());

  public static final String OAUTH_TOKEN_PROP =
      "mail.imaps.sasl.mechanisms.oauth2.oauthToken";

  public SaslClient createSaslClient(String[] mechanisms,
                                     String authorizationId,
                                     String protocol,
                                     String serverName,
                                     Map<String, ?> props,
                                     CallbackHandler callbackHandler) {
    boolean matchedMechanism = false;
    for (int i = 0; i < mechanisms.length; ++i) {
      if ("XOAUTH2".equalsIgnoreCase(mechanisms[i])) {
        matchedMechanism = true;
        break;
      }
    }
    if (!matchedMechanism) {
      logger.info("Failed to match any mechanisms");
      return null;
    }
    return new OAuth2SaslClient((String) props.get(OAUTH_TOKEN_PROP),
                                callbackHandler);
  }

  public String[] getMechanismNames(Map<String, ?> props) {
    return new String[] {"XOAUTH2"};
  }
}

class OAuth2SaslClient implements SaslClient {
	private static final Logger logger = Logger.getLogger(OAuth2SaslClient.class.getName());

	private final String oauthToken;
	private final CallbackHandler callbackHandler;

	private boolean isComplete = false;

	/**
	 * Creates a new instance of the OAuth2SaslClient. This will ordinarily only be
	 * called from OAuth2SaslClientFactory.
	 */
	public OAuth2SaslClient(String oauthToken, CallbackHandler callbackHandler) {
		this.oauthToken = oauthToken;
		this.callbackHandler = callbackHandler;
	}

	public String getMechanismName() {
		return "XOAUTH2";
	}

	public boolean hasInitialResponse() {
		return true;
	}

	public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
		if (isComplete) {
			// Empty final response from server, just ignore it.
			return new byte[] {};
		}

		NameCallback nameCallback = new NameCallback("email");
		PasswordCallback passwordCallback = new PasswordCallback("password", false);
		Callback[] callbacks = new Callback[] { nameCallback, passwordCallback };
		try {
			callbackHandler.handle(callbacks);
		} catch (UnsupportedCallbackException e) {
			throw new SaslException("Unsupported callback: " + e);
		} catch (IOException e) {
			throw new SaslException("Failed to execute callback: " + e);
		}
		String email = nameCallback.getName();

		byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", email, oauthToken).getBytes();
		isComplete = true;
		return response;
	}

	public boolean isComplete() {
		return isComplete;
	}

	public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException {
		throw new IllegalStateException();
	}

	public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException {
		throw new IllegalStateException();
	}

	public Object getNegotiatedProperty(String propName) {
		if (!isComplete()) {
			throw new IllegalStateException();
		}
		return null;
	}

	public void dispose() throws SaslException {
	}
}


public static final class OAuth2Provider extends Provider {
		private static final long serialVersionUID = 1L;

		public OAuth2Provider() {
			super("Google OAuth2 Provider", 1.0, "Provides the XOAUTH2 SASL Mechanism");
			put("SaslClientFactory.XOAUTH2", "com.email.oauth.OAuth2SaslClientFactory");
		}
	}

	public void authenticate(String args[]) throws Exception {
		if (args.length != 2) {
			System.err.println("Usage: OAuth2Authenticator <email> <oauthToken>");
			return;
		}
		String email = args[0];
		String oauthToken = args[1];

		Security.addProvider(new OAuth2Provider());
		System.out.println(oauthToken);
		IMAPStore imapStore = connectToImap("imap.gmail.com", 993, email, oauthToken, true);
		Folder[] folders = imapStore.getPersonalNamespaces();
		System.out.println(folders);
		System.out.println("Successfully authenticated to IMAP.\n");
	}


                Properties props = new Properties();
		props.put("mail.imaps.sasl.enable", "true");
		props.put("mail.debug.auth", "true");
		props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
		props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
		Session session = Session.getInstance(props);
		session.setDebug(debug);
		final URLName unusedUrlName = null;
		IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
		final String emptyPassword = "app passowrd";
		store.connect(host, port, userEmail, emptyPassword);

 

 

 

 

 

Failure Logs:

DEBUG IMAPS: SASL client XOAUTH2
DEBUG IMAPS: SASL callback length: 2
DEBUG IMAPS: SASL callback 0: javax.security.auth.callback.NameCallback@2c5be2fe
DEBUG IMAPS: SASL callback 1: javax.security.auth.callback.PasswordCallback@285fa04b
B1 AUTHENTICATE XOAUTH2
DEBUG IMAPS: SASL no response

B1 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)
jakarta.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:708)
at jakarta.mail.Service.connect(Service.java:345)
at com.email.Application.connectToImap(Application.java:101)
at com.email.Application.authonticate(Application.java:54)
at com.email.Application.main(Application.java:37)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50)

 

 

 

 

 

 

 

Solved Solved
0 1 496
1 ACCEPTED SOLUTION

Hi @coding-ex,

Welcome to the Google Cloud Community!

Just a heads up, Gmail is part of the Google Workspace lineup of products and has its own dedicated developer community, so I recommend re-posting your question on the Google Workspace forums instead for better visibility with our Google Developer Experts (GDEs).

For reference, you may also post your thread on these channels for more assistance:

If these didn’t resolve the issue, find more support for the Gmail API here.

Was my response helpful? If so, feel free to accept this answer as “Solution”. If you need any additional assistance with Google Cloud, you may also reply here within two business days.

View solution in original post

1 REPLY 1

Hi @coding-ex,

Welcome to the Google Cloud Community!

Just a heads up, Gmail is part of the Google Workspace lineup of products and has its own dedicated developer community, so I recommend re-posting your question on the Google Workspace forums instead for better visibility with our Google Developer Experts (GDEs).

For reference, you may also post your thread on these channels for more assistance:

If these didn’t resolve the issue, find more support for the Gmail API here.

Was my response helpful? If so, feel free to accept this answer as “Solution”. If you need any additional assistance with Google Cloud, you may also reply here within two business days.

Top Solution Authors