I’ve been working on a web portal that users Azure Active Directory (AAD) for user authentication and for requesting permissions to the Azure Graph API, the code for which is based on this sample project.
This uses a library called Microsoft.Identity.Web that assists with acquiring and storing tokens, currently this library needs to be added manually but it seems like it should be deployed to NuGet soon.
The main issue I had with getting caching of tokens working as in the sample project was that although these seemed to be added initially they didn’t persist and I was receiving the following error when trying to retrieve tokens from the cache.
MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call
There’s 3 options for caching tokens in the Microsoft.Identity.Web library, Memory, Session and SQL. In Memory caching loses saved tokens each time the app is restarted as these are held in memory but the AAD login is persisted so although the user doesn’t need to login again when the app is restarted the token lookup will return nothing and the above error will be returned. The session caching doesn’t seem to actually save tokens to the session but that may be due to some weird interactions with my browser or ad blockers. The only one that worked for me was SQL caching which acted as a persistent token store.
In order to set up the SQL caching I needed to create the following tables and grant my SQL service account access to them, after that was done everything ran smoothly.
AppTokenCache.sql
CREATE TABLE [dbo].[AppTokenCache]
(
[AppTokenCacheId] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[ClientID] VARCHAR(255) NOT NULL,
[CacheBits] VARBINARY(MAX) NOT NULL,
[LastWrite] DATETIME NOT NULL,
[RowVersion] VARBINARY(255)
)
GO
UserTokenCache.sql
CREATE TABLE [dbo].[UserTokenCache]
(
[UserTokenCacheId] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
[WebUserUniqueId] VARCHAR(255) NOT NULL,
[CacheBits] VARBINARY(MAX) NOT NULL,
[LastWrite] DATETIME NOT NULL,
[RowVersion] VARBINARY(255)
)
GO
5 Comments
Joseph · 6th February 2020 at 10:14 am
Hi,
Can you provide an example of you the SQL implementation? You must have created a MsalSqlTokenCacheProvider?
Shinigami · 6th February 2020 at 11:12 am
I copied the SQL provider from the Microsoft.Identity.Web project linked above, though it looks like they’ve removed it now as it should be available through ASP.NET Core apparently.
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/commit/db1033395664ca6c6cb370696800e253c0bb6a25#diff-e49a2164810c49a83805096c34a7699d
I’ve uploaded the files here if you need them.
https://bitscry.blob.core.windows.net/public/TokenCacheProviders/Sql.7z
Skriker · 23rd April 2020 at 9:52 am
I built a working sample app using this – https://docs.microsoft.com/en-us/learn/modules/msgraph-build-aspnetmvc-apps/6-add-graph
However when app is restarted its lost the token, can your above code work with this sample?
Shinigami · 23rd April 2020 at 11:03 am
Hi, I’m assuming you’re getting the same issue as I was with the session cache being cleared. If you wnat to properly persist tokens then you’ll need to use a token store such as SQL rather than an in-memory one.
Have a look at the sample here.
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-2-TokenCache
I think things have moved on a bit since I originally posted this so I’d suggest following the example linked above, this provides details of how to cahe tokens with SQL Server.
https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/2-WebApp-graph-user/2-2-TokenCache#about-the-code
Skriker · 23rd April 2020 at 1:26 pm
Great, thanks for this.