0

I am trying to access my own OneNote notebooks using the MSGraph API.

It has taken a lot of effort, but I have eventually worked out how to get an access token and can successfully send a request to "https://graph.microsoft.com/v1.0/me" and get my own details returned.

However, when I try to send a request to "https://graph.microsoft.com/v1.0/me/onenote/pages", I get an error: {"error":{"code":"30108","message":"OneDrive for Business for this user account cannot be retrieved." etc.

My OneNote and OneDrive are just the free ones that come with Windows (no subscriptions).

I'm beginning to think I maybe need a subscription for this to work, but I was wondering if I am maybe using the wrong end-point and would be grateful for any advice.

Thanks.

I have tried other endpoints (Microsoft seem to change how you obtain authentication a lot! The most recent stackoverflow questions are from around 2020 but things seem to have changed again since then and do not answer my question) but always get this error or another one about Sharepoint (sorry, didn't take a note of this one!).

1 Answers1

0

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;
}

} ` enter image description here

enter image description here

  • Are you getting a different error now? Also share your current code – scottwtang Aug 27 '23 at 19:47
  • I think I have a good idea of why this isn't working, but I need to see your code, including how you're getting an access token, and screenshots of the App Registration blades for Authentication and API Permissions would help (private data blurred out) – scottwtang Aug 28 '23 at 22:22