Yahoo, finally found an answer.
To answer my own question in case it can save someone else the hours I spent on this!
There was something wrong with the way my app was set up in Azure Active Directory. When I originally set it up, there was no option for "personal accounts". I later went back and edited the Manifest, which looked to have worked when I looked at the app in Azure.
I eventually decided to set up a new app in active directory. This time there was an option for "personal Accounts" and when I changed my code to point to the id of this app, everything worked perfectly.
I had updated to the "£1.99 per month 365 Basic Account" so can't rule out that this wasn't necessary, but I suspect it would work with a free account too?
Update 27/08/2023 - I allowed my 365 Basic Account to expire and it stopped working again! I've resubscribed but still not working after a couple of days. Thinking of giving up on this!
Update 28/0/2023 - The error message has changed, it is now :
com.microsoft.identity.client.exception.MsalClientException: {"code":"invalid_request","message":"Error: 'invalid_tenant' Description: 'AADSTS90002: Tenant '*****' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Check with your subscription administrator, this may happen if there are no active subscriptions for the tenant.'","operation":"Discovery","subcode":"invalid_tenant","time":"08-28-2023 21:17:27Z"}
I'm not sure which part of my code to post, but I think the problem is in the way my Azure Active Directory is set up rather than my code. When I checked "subscriptions" in the Azure Portal, it said I had none, so I have added one, but that doesn't seem to have fixed the problem.
I'm wondering now if it maybe worked originally because I maybe had a free one month trial subscription? To be honest, for all I want to use it for, I'm beginning to wonder if it's worth the hastle!
29/08/2023 Thanks for the help scottwtang, I really don't want to spend too much time on this, its more an announce than something vital to my app so obviously, don't waste too much of your own time on it, but here's what I think are the important bits of code :
void searchOneNote() { PublicClientApplication.createSingleAccountPublicClientApplication(this,
R.raw.auth_config_single_account,
new IPublicClientApplication.ISingleAccountApplicationCreatedListener() {
@Override
public void onCreated(ISingleAccountPublicClientApplication application) {
mSingleAccountApp = application;
loadAccount();
}
@Override
public void onError(MsalException exception) {
exception.toString();
}
});
}
//ONENOTE SECTION
private static String[] getScopes() {
return "user. Read notes.read".toLowerCase().split(" ");
}
private void callGraphAPI(final IAuthenticationResult authenticationResult) {
Thread thread = new Thread(() -> {
final IAuthenticationProvider authProvider = new MyAuthenticationProvider(authenticationResult.getAccessToken());
GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
LinkedList<Option> requestOptions = new LinkedList<>();
requestOptions.add(new QueryOption("search", "'" + searchterm + "'"));
try {
OnenotePageCollectionPage pages = graphClient.me().onenote().pages()
.buildRequest(requestOptions)
.get();
List<OnenotePage> pages2 = pages.getCurrentPage();
for (int i = 0; i < pages2.size(); i++) {
ONENOTEFOUND = 1;
OnenotePage page = pages2.get(i);
PageLinks links = page. Links;
String link = links.oneNoteClientUrl.href
}
} catch (GraphServiceException e) {
String debug3 = e.toString();
debug3.length();
}
});
thread. Start();
}
private void loadAccount() {
if (mSingleAccountApp == null) {
return;
}
mSingleAccountApp.getCurrentAccountAsync(new ISingleAccountPublicClientApplication.CurrentAccountCallback() {
@Override
public void onAccountLoaded(@Nullable IAccount activeAccount) {
initializeGraph();
}
@Override
public void onAccountChanged(@Nullable IAccount priorAccount, @Nullable IAccount currentAccount) {
if (currentAccount == null) {
// Perform a cleanup task as the signed-in account changed.
}
}
@Override
public void onError(@NonNull MsalException exception) {
}
});
}
private AuthenticationCallback getAuthInteractiveCallback() {
return new AuthenticationCallback() {
@Override
public void onSuccess(IAuthenticationResult authenticationResult) {
/* Successfully got a token, use it to call a protected resource - MSGraph */
/* Update account */
mAccount = authenticationResult.getAccount();
/* call graph */
callGraphAPI(authenticationResult);
}
@Override
public void onError(MsalException exception) {
/* Failed to acquireToken */
if (exception.toString().equals("com.microsoft.identity.client.exception.MsalClientException: An account is already signed in.")) {
SignInParameters signInParameters = SignInParameters.builder()
.withScopes(Arrays.asList(getScopes()))
.withCallback(getAuthInteractiveCallback())
.withActivity(SearchAllActivity.this)
.build();
mSingleAccountApp.signInAgain(signInParameters);
}
else if (exception instanceof MsalClientException) {
/* Exception inside MSAL, more info inside MsalError.java */
} else if (exception instanceof MsalServiceException) {
/* Exception when communicating with the STS, likely config issue */
}
}
@Override
public void onCancel() {
/* User canceled the authentication */
Log.d(TAG, "User cancelled login.");
}
};
}
//ONENOTE SECTION ENDS
`
auth_config_single_account.json
{ "client_id" : "", "authorization_user_agent" : "DEFAULT", "redirect_uri" : "msauth://com.mydumfries.mydiary/", "account_mode": "SINGLE", "authorities": [ { "type": "AAD", "audience": { "type": "AzureADandPersonalMicrosoftAccount", "tenant_id": "common" } } ] }
`public class MyAuthenticationProvider implements IAuthenticationProvider {
final private CompletableFuture<String> accessTokenFuture;
public MyAuthenticationProvider(String accessToken) {
this.acce`ssTokenFuture = new CompletableFuture<>();
this.accessTokenFuture.complete(accessToken);
}
@Override
public CompletableFuture<String> getAuthorizationTokenAsync(URL requestUrl) {
return this.accessTokenFuture;
}
}
`

