Skip to content

Access Token is not refresh on SPFx Personal Teams App on Android Mobile - Unable to Call Graph API #10673

@Hugo-Hanus

Description

@Hugo-Hanus

Target SharePoint environment

SharePoint Online

What SharePoint development model, framework, SDK or API is this about?

💥 SharePoint Framework

Developer environment

None

What browser(s) / client(s) have you tested

  • 💥 Internet Explorer
  • 💥 Microsoft Edge
  • 💥 Google Chrome
  • 💥 FireFox
  • 💥 Safari
  • mobile (iOS/iPadOS)
  • mobile (Android)
  • not applicable
  • other (enter in the "Additional environment details" area below)

Additional environment details

  • Android : 15.0
  • Phone : Nothing (1)
  • Teams Version : 1416/1.0.0.2026023402/0209
  • First App tested
    • SPFx version : 1.18.2
    • Node.js version : 18.20.8
      • @pnp/graph: 3.18.0
      • @pnp/sp : 3.18.0
  • Second App tested
    • SPFx version : 1.21.1
    • Node.js version : 22.15.0
      • @pnp/graph: 4.13.0
      • @pnp/sp: 4.13.0

Describe the bug / error

Description

Since the beginning of the year, Microsoft has enhanced the security for authentication of Android base Teams devices MC1088732. With this changes , the authentication/access token expired faster (approximately 1 hour) and is not refresh automatically in SPFx webpart in Teams Personal App on android Mobile.

Because of this, we are unable to call Graph's API with web API permission (User.ReadBasic.All, etc) in SPFx webpart

I have the same issue on all tenants i have access to (more than 4). In all of these tenants, MFA are applied on each tenant.(The API permissions User.ReadBasic.All is also authorized on all tenants)

I tried to log the error using my mobile phone and i got this error :

Error making HttpClient request in queryable [401]  ::> {"error":{"code":"InvalidAuthenticationToken","message":"Lifetime validation failed, the token is expired."}}

Other colleges tried on their phones ( Google Pixel,Samsung with Android 16) and they have the same error by reproducing the same step (5 to 7) has describe below.

There is not links with network or organization settings.

I also tried on a second app in 1.21.1 with same error

I also tried with my webpart on a SharePoint Site by using the SharePoint Application on my android device and the Graph's call is working.

Workaround

If i sign-out and sing-in, the token if refresh and the Graph's API call works. But after approximately 1 hour, the access token expired, and the API call fails.

Questions

If it's the intended behavior of the Microsoft Changes MC1088732.
Do we simply need to update our Teams App version to 1449 and it's resolved ?
Or do we need to implement, in our apps, the refresh the access token ?

Thank you for your feedback !

Steps to reproduce

  1. Create a SPFx webpart
  2. Configure webApiPersmissionRequests in package-solution.json
"webApiPermissionRequests": [
     {
       "resource": "Microsoft Graph",
       "scope": "User.ReadBasic.All"
     }
   ]
  1. Validate webApiPermission for User.ReadBasic.All in SharePoint Admin
  2. Make a Call using Graph API ( for ex: /me) by using choosing one if these options :
  • PnP/Graph
import { Version } from "@microsoft/sp-core-library";
import { IPropertyPaneConfiguration } from "@microsoft/sp-property-pane";
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import { ITheme, loadTheme } from "@fluentui/react";
import * as React from "react";
import * as ReactDom from "react-dom";
import Context from "../../services/Context";
import App from "./components/App";
import { SPFx as spSPFx } from "@pnp/sp";
import { SPFx as graphSPFx } from "@pnp/graph";
import { graph } from "@pnp/graph";
export default class ContosoAppWebPart extends BaseClientSideWebPart<never> {
  public render(): void {
    const element: React.ReactElement = React.createElement(App, {
      context: this.context,
    });

    ReactDom.render(element, this.domElement);
  }

  protected onThemeChanged(theme: ITheme | undefined): void {
    if (theme) loadTheme(theme);
  }

  protected onInit(): Promise<void> {
    graph.using(graphSPFx(this.context));
    await graph.me();
    return super.onInit();
  }

  protected onDispose(): void {
    ReactDom.unmountComponentAtNode(this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse("1.0");
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [],
    };
  }
}
  • ServiceScope and the AadHttpClientFactory
    • App
import { Version } from "@microsoft/sp-core-library";
import { IPropertyPaneConfiguration } from "@microsoft/sp-property-pane";
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import { initializeIcons, ITheme, loadTheme } from "@fluentui/react";
import * as React from "react";
import * as ReactDom from "react-dom";
import App from "./components/App";
import { IContosoApp} from "./components/ContosoAppProps";
import { GraphService } from "../../services/GraphService/GraphService";


export default class ContosoAppWebPart extends BaseClientSideWebPart<never> {
 private _graphService: GraphService;

 public render(): void {
   const element: React.ReactElement<IContosoAppProps> = React.createElement(App, {
     context: this.context,
     clientWidth: this.context.domElement.clientWidth,
     graphService: this._graphService
   });

   ReactDom.render(element, this.domElement);
 }

 protected onThemeChanged(theme: ITheme | undefined): void {
   if (theme) loadTheme(theme);
 }

 protected async onInit(): Promise<void> {
   if (this.context.sdks.microsoftTeams) initializeIcons();

   this._graphService = this.context.serviceScope.consume(GraphService.serviceKey);
   return super.onInit();
 }

 protected onDispose(): void {
   ReactDom.unmountComponentAtNode(this.domElement);
 }

 protected get dataVersion(): Version {
   return Version.parse("1.0");
 }

 protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
   return {
     pages: []
   };
 }
}```
   - ServiceScope
 ```typescript
import { ServiceKey, ServiceScope } from "@microsoft/sp-core-library";
import { AadHttpClient, AadHttpClientFactory } from "@microsoft/sp-http";
import { IUser } from "../../models/User";

export class GraphService {
 private static readonly graphBaseUrl: string = "https://graph.microsoft.com/v1.0";

 public static readonly serviceKey: ServiceKey<IGraphService> = ServiceKey.create<IGraphService>(
   "Custom:GraphService",
   GraphService
 );

 private _aadHttpClientFactory: AadHttpClientFactory;

 constructor(serviceScope: ServiceScope) {
   serviceScope.whenFinished(() => {
     this._aadHttpClientFactory = serviceScope.consume(AadHttpClientFactory.serviceKey);
   });
 }

 /**
  * Fetch the current user.
  */
 public async getCurrentUser(): Promise<IUser> {
   try {
     const aadClient: AadHttpClient = await this._aadHttpClientFactory.getClient(
       "https://graph.microsoft.com"
     );
     const response = await aadClient.get(
       `https://graph.microsoft.com/v1.0/me`,
       AadHttpClient.configurations.v1
     );

     if (!response.ok) {
       throw new Error(`Error fetching current user: ${response.statusText}`);
     }

     const user: IUser = await response.json();
     return user;
   } catch (error) {
     console.error("Error in getCurrentUser:", error);
     throw error;
   }
 }
}
export const GraphServiceKey = ServiceKey.create<IGraphService>(
 "my-custom.GraphService",
 GraphService
);
  1. Create a Teams Personal App using the SPFx Webpart
  2. Launch the App on a android mobile.
  3. Close your Teams and wait +-1 hour until the access token expired.
  4. Launch the App again

Expected behavior

The webpart will return a error if the access token expired :

Error making HttpClient request in queryable [401]  ::> {"error":{"code":"InvalidAuthenticationToken","message":"Lifetime validation failed, the token is expired."}}```

Metadata

Metadata

Assignees

Labels

area:spfx-msteamsCategory: SharePoint Framework & Microsoft Teams supportsharepoint-developer-supportsharepoint-developer-supporttype:bug-suspectedSuspected bug (not working as designed/expected). See “type:bug-confirmed” for confirmed bugs.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions