Reputation: 106
I am implementing MSAL authentication for our SPA. I've followed various official and unofficial guides and so far this is my auth implementation:
loginMicrosoft() {
myMSALObj
.loginPopup(msalConfig.loginRequest)
.then((response) => {
console.log(response);
this.username = response.account.userName;
this.account = response.account;
})
.catch((error) => {
console.error(error);
});
},
readEvents() {
this.getTokenPopup(msalConfig.tokenRequest)
.then((response) => {
console.log("silent token!: ", response);
this.callMSGraph(
graphConfig.graphConfig.graphGetCalendarEventsEndpoint,
response.accessToken
);
})
.catch((error) => {
console.error(error);
});
},
createEvent() {
this.getTokenPopup(msalConfig.tokenRequest)
.then((response) => {
this.callMSGraphCreateEvent(
graphConfig.graphConfig.graphCreateCalendarEventEndpoint,
response.accessToken
);
})
.catch((error) => {
console.error(error);
});
},
getTokenPopup(request) {
request.account = this.account;
console.log(request);
return myMSALObj.acquireTokenSilent(request).catch((error) => {
console.warn(
"silent token acquisition fails. acquiring token using popup : ",
error
);
if (error instanceof Msal.InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return myMSALObj
.acquireTokenPopup(request)
.then((tokenResponse) => {
console.log(tokenResponse);
return tokenResponse;
})
.catch((error) => {
console.error(error);
});
} else {
console.warn(error);
}
});
},
async callMSGraph(endpoint, token) {
console.log("request made to Graph API at: " + new Date().toString());
const resp = await axios.post("/api/microsoft/get-events", { endpoint, token });
this.calendarEvents = resp.data.value;
console.log("vaste: ", resp);
},
async callMSGraphCreateEvent(endpoint, token) {
console.log("request made to Graph API at: " + new Date().toString());
const resp = await axios.post("/api/microsoft/create-event", {
endpoint,
token,
});
this.calendarEvents = resp.data.value;
console.log("vaste: ", resp);
},
Everything works as intended, until the access token is reaching expiry. If AcquireTokenSilent is called 5 minutes before the expiration of after the expiration of the access token, I would expect it to return a new access token, using the hidden refresh token in the MSAL cache. Instead, I get the following error:
silent token acquisition fails. acquiring token using popup : InteractionRequiredAuthError: Silent authentication was denied. The user must first sign in and if needed grant the client application access to the scope 'User.Read Calendars.ReadWrite openid profile'.
It doesn't seem to be normal to ask for user sign-in every hour, and I cant seem to find any resources on this issue..
Any help is greatly appreciated!
EDIT:
I tried adding offline_access to my token request scopes. My scopes setup is following:
export const loginRequest = {
scopes: ["User.Read", "Calendars.ReadWrite", "offline_access"],
};
export const tokenRequest = {
scopes: ["User.Read", "Calendars.ReadWrite", "offline_access"],
forceRefresh: false, // Set this to "true" to skip a cached token and go to the server to get a new token
};
Now im getting the login popup with the following error every time i try to call the api:
InteractionRequiredAuthError: Silent authentication was denied. The user must first sign in and if needed grant the client application access to the scope 'User.Read Calendars.ReadWrite offline_access openid profile'.
Upvotes: 3
Views: 6028
Reputation: 12245
Probably your scopes (in your app registration or in your msal config, depending on where you define your config and if you are using .default
scope) do not include the request for the offline_access
scope. Please include it, it is required if you want to (auto-) refresh your tokens. If you don't get a new consent prompt after adding this scope (user must agree, i.e. give consent to this), just reset your app consents in azure portal, or consent manually.
Upvotes: 1