Skip to content
This repository has been archived by the owner on Jun 18, 2024. It is now read-only.

How to Authenticate an EWS application by using OAuth? #748

Open
Chandler54321 opened this issue Nov 30, 2021 · 11 comments
Open

How to Authenticate an EWS application by using OAuth? #748

Chandler54321 opened this issue Nov 30, 2021 · 11 comments

Comments

@Chandler54321
Copy link

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
How to Authenticate an EWS application by using OAuth in Java?
Thanks

@Chandler54321
Copy link
Author

`public final class BearerTokenCredentials extends ExchangeCredentials {

private static final String BEARER_TOKEN_FORMAT_REGEX = "^[-._~+/A-Za-z0-9]+=*$";
private static final String AUTHORIZATION = "Authorization";
private static final String BEARER_AUTH_PREAMBLE = "Bearer ";
private String token;

public String getToken() {
    return token;
}

public BearerTokenCredentials(String bearerToken) {
    if (bearerToken == null) {
        throw new IllegalArgumentException("Bearer token can not be null");
    }
    this.validateToken(bearerToken);
    this.token = bearerToken;
}

protected void validateToken(String bearerToken) throws IllegalArgumentException {
    if (!bearerToken.matches(BEARER_TOKEN_FORMAT_REGEX)) {
        throw new IllegalArgumentException("Bearer token format is invalid.");
    }
}

@Override
public void prepareWebRequest(HttpWebRequest request) {
    Map<String, String> headersMap = request.getHeaders();
    String bearerValue = BEARER_AUTH_PREAMBLE + token;
    headersMap.put(AUTHORIZATION, bearerValue);
    request.setHeaders(headersMap);
}

}`

` String email = "emailaddressxx";
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.setTraceEnabled(true);
BearerTokenCredentials credentials = new BearerTokenCredentials(MsEwsTokenProvider.getAccesToken());
service.setCredentials(credentials);
service.setUrl(new URI("https://" + "outlook.office365.com" + "/EWS/Exchange.asmx"));
service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.SmtpAddress, email));

    // Bind to the Inbox.
    Folder inbox = Folder.bind(service, WellKnownFolderName.Inbox);
    int count = inbox.getTotalCount();
    System.out.println(inbox.getDisplayName());
    ItemView itemView = new ItemView(count);
    //
    FindItemsResults<Item> findResults = service.findItems(inbox.getId(), itemView);
    ArrayList<Item> items = findResults.getItems();
    for (int i = 0; i < items.size(); i++) {
        EmailMessage message = EmailMessage.bind(service, items.get(i).getId());
        message.load();
        System.out.println(message.getSender());
    }

But return 401Exception in thread "main" microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException: The request failed. The request failed. The remote server returned an error: (401)Unauthorized
at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:74)
at microsoft.exchange.webservices.data.core.request.MultiResponseServiceRequest.execute(MultiResponseServiceRequest.java:158)
at microsoft.exchange.webservices.data.core.ExchangeService.bindToFolder(ExchangeService.java:504)
at microsoft.exchange.webservices.data.core.ExchangeService.bindToFolder(ExchangeService.java:523)
at microsoft.exchange.webservices.data.core.service.folder.Folder.bind(Folder.java:98)
at microsoft.exchange.webservices.data.core.service.folder.Folder.bind(Folder.java:147)
at ReadExchangeMail.main(ReadExchangeMail.java:64)
Caused by: microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException: The request failed. The remote server returned an error: (401)Unauthorized
at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.validateAndEmitRequest(ServiceRequestBase.java:644)
at microsoft.exchange.webservices.data.core.request.SimpleServiceRequestBase.internalExecute(SimpleServiceRequestBase.java:62)
... 6 more
Caused by: microsoft.exchange.webservices.data.core.exception.http.HttpErrorException: The remote server returned an error: (401)Unauthorized
at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.getEwsHttpWebResponse(ServiceRequestBase.java:723)
at microsoft.exchange.webservices.data.core.request.ServiceRequestBase.validateAndEmitRequest(ServiceRequestBase.java:639)
... 7 more`

@davidmoten
Copy link

Can you show us MsEwsTokenProvider.java? By the way use triple back ticks for blocks of code (not single back ticks).

@Chandler54321
Copy link
Author

`public final class MsEwsTokenProvider {

private static final String EWS_URL = "https://outlook.office365.com/EWS/Exchange.asmx";
private static String scope = "https://outlook.office.com/.default";

private static String clientId = "xxxxx";
private static String secret = "xxxxx";
private static String authority = "https://login.microsoftonline.com/xxxxx/";


public static String getAccesToken() throws Exception {

    ConfidentialClientApplication app = ConfidentialClientApplication.builder(
            clientId,
            ClientCredentialFactory.createFromSecret(secret))
            .authority(authority)
            .build();

    // With client credentials flows the scope is ALWAYS of the shape "resource/.default", as the
    // application permissions need to be set statically (in the portal), and then granted by a tenant administrator
    ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
            Collections.singleton(scope))
            .build();

    CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
    System.out.println(future.get().accessToken());
    return future.get().accessToken();
}`

I can got the token,but can not get the mail inbox. Thanks

@davidmoten
Copy link

Yeah but if you are getting a 401 it means that the token doesn't authenticate you. I guess it could be a permission problem and the service is giving you a 401 instead of the appropriate 403.

@davidmoten
Copy link

Triple ticks please, formatting gets stuffed up.

@davidmoten
Copy link

@Egis-Devandrin
Copy link

@davidmoten @Chandler54321

Any idea how to resolve it tho?

On the EWS docs, theres two types of Authentication, Delegated and App only
Where delegated uses specific permissions but I keep getting a 401 unauthorised, but Authentication via Application Auth works 100%

@davidmoten
Copy link

@Chandler54321 I notice that our code (that works fine) does this step:

service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.PrincipalName, email));

You might want to try that instead of your line:

service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.SmtpAddress, email));

@Rakshana113
Copy link

BearerTokenCredentials credentials = new BearerTokenCredentials(MsEwsTokenProvider.getAccesToken()); service.setCredentials(credentials);
I am getting setCredentials is not applicable for BearerTokenCredentials .kindly help me out.
Thanks in Advance!

@internationalJoke
Copy link

You answer is quite helpful to me, Thanks a lot.

@internationalJoke
Copy link

internationalJoke commented Jul 27, 2022

BearerTokenCredentials credentials = new BearerTokenCredentials(MsEwsTokenProvider.getAccesToken()); service.setCredentials(credentials); I am getting setCredentials is not applicable for BearerTokenCredentials .kindly help me out. Thanks in Advance!

Did your BearerTokenCredentials class extend ExchangeCredentials?
"public class BearerTokenCredentials extends ExchangeCredentials" works well here.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants