Sending custom parameter on authentication - servicestack

I'm a servicestack newbie. I'm trying to figure out how to send custom parameter on authentication.
As far as I understood, that's the step to authenticate a client and than execute a set of call within a session
var jsonClient = new JsonServiceClient("http://localhost:55679/");
var authResponse = client.Send(new Authenticate
{
provider = "myProvider",
UserName = "user",
Password = "pwd",
RememberMe = true,
});
var jResponse = jsonClient.Get<CountriesResponse>(request);
Console.WriteLine(jResponse.Countries.Count);
So far so good, I configurated my apphost as following and everything works as expected.
Plugins.Add(new AuthFeature(() => new CustomUserSession(), new IAuthProvider[] {
new MyAuthProvider(),
}));
What should I do if, instead of sending ServiceStack.Authenticate, I'd like to send my MyAuthenticate
request that has same custom properties, somenthing like this?
var authResponse = client.Send(new MyAuthenticate
{
provider = "myProvider",
UserName = "user",
Password = "pwd",
RememberMe = true,
AppId = "AppId",
ProjectId = "ProjectId"
});
My goal is to send custom parameter while I'm authenticating the user, not just those allowed by Authenticate built-in request, and than store those extra parameter within my CustomUserSession.
Thanks

Sending additional info on QueryString or HttpHeaders
As you can't change the built-in Authenticate Request DTO, one way to send additional metadata is to add extra info on the QueryString or HTTP Headers.
If you wanted to use the .NET Service Clients to do this you would need to use the RequestFilter, e.g:
var client = new JsonServiceClient(BaseUrl) {
RequestFilter = req => {
req.QueryString["AppId"] = appId;
req.QueryString["ProjectId"] = appId;
}
};
var authResponse = client.Send(new Authenticate { ... });
Otherwise creating custom Request is often more flexible using ServiceStack's built-in HTTP Utils, e.g:
var url = "{0}/auth/myProvider".Fmt(BaseUrl)
.AddQueryParam("AppId", appId)
.AddQueryParam("ProjectId", projectId);
var authResponse = url.PostJsonToUrl(new Authenticate { ... });
On the server the additional data will be available in the QueryString of the current request which you can get from IServiceBase or IRequest args, e.g:
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
...
public override IHttpResult OnAuthenticated(IServiceBase authService,
IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
...
var customSession = (CustomUserSession)session;
customSession.AppId = authService.Request.QueryString["AppId"];
customSession.ProjectId = authService.Request.QueryString["ProjectId"];
return base.OnAuthenticated(authService, session, tokens, authInfo);
}
}
Custom Meta dictionary now available on Authenticate Request DTO
To make this use-case a little easier a new Dictionary<string,string> Meta property was added on the Authenticate DTO which makes calling from the Typed Service Clients a little nicer since you don't have to use a filter, e.g:
var client = new JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate {
...
Meta = new Dictionary<string, string> { {"AppId", appId}, {"ProjectId", pId} },
});
Which you can access from the Authenticate DTO directly, e.g:
var authRequest = (Authenticate)authService.Request.Dto;
customSession.AppId = authRequest.Meta["AppId"];
customSession.ProjectId = authRequest.Meta["ProjectId"];
The new Meta property is available from v4.0.35+ that's currently available on MyGet.
Use your own Custom Authentication Service
A more disruptive alternative approach to be able to use your own MyAuthenticate DTO is to handle the authentication request in your own Service and then delegate to the AuthService, e.g:
public class MyAuthenticate : Authenticate
{
public string AppId { get; set; }
public string ProjectId { get; set; }
}
public class MyAuthServices : Service
{
public object Any(MyAuthenticate request)
{
using (var auth = base.ResolveService<AuthenticateService>())
{
var response = auth.Post(request);
var authResponse = response as AuthenticateResponse;
if (authResponse != null) {
var session = base.SessionAs<CustomUserSession>();
session.AppId = request.AppId;
session.ProjectId = request.ProjectId;
this.SaveSession(session);
}
return response;
}
}
}

Related

Blazor Server SignalR Chat works on Local, not on Azure

I have a working Blazor Server application with a Chat component running locally correctly, using signal R hub connection.
When deploying to Azure, I receive error Invalid negotiation response received.---> System.Text.Json.JsonReaderException: '0x1F' is an invalid start of a value.
Here is a similar linked ticket, but it was never answered: Blazor Server SignalR hub fails on StartAsync due to Azure ADB2C
Goal: Create a private chat feature for Blazor server application. I am unable to use singleton service because all users cant share the same instance of the service.
I have yet to find a sample where there is a messaging feature between users/usergroups in blazor server.
Since I am using Azure B2C auth with OIDC default authentication scheme, I have to manually pass the cookies and the headers.
Like I mentioned, this sample is working perfectly on localhost, when I open up two browsers (one in incognito), i am able to send messages between logged in users. When I publish to Azure App Service, however, I am unable to connect to the hub.
Code:
private HubConnection _hubConnection;
private User user;
ObservableCollection<Message> messages = new ObservableCollection<Message>();
SfTextBox MessageBox;
SfTextBox SendTo;
public class Message
{
public string Id { get; set; }
public string UserName { get; set; }
public string MessageText { get; set; }
public string Chat { get; set; }
}
protected override async Task OnInitializedAsync()
{
var state = await authenticationStateProvider.GetAuthenticationStateAsync();
user = state.ToUser();
_hubConnection = new HubConnectionBuilder()
.WithUrl(navigationManager.ToAbsoluteUri("/chatHub"), options =>
{
options.UseDefaultCredentials = true;
var httpContext = HttpContextAccessor.HttpContext;
var cookieCount = httpContext.Request.Cookies.Count();
var cookieContainer = new System.Net.CookieContainer(cookieCount);
foreach (var cookie in httpContext.Request.Cookies)
cookieContainer.Add(new System.Net.Cookie(
cookie.Key,
WebUtility.UrlEncode(cookie.Value),
path: httpContext.Request.Path,
domain: httpContext.Request.Host.Host));
options.Cookies = cookieContainer;
NameValueHeaderValue headers = null;
foreach (var header in httpContext.Request.Headers)
{
if (header.Key != ":method")
options.Headers.Add(header.Key, header.Value);
}
options.HttpMessageHandlerFactory = (input) =>
{
var clientHandler = new HttpClientHandler
{
PreAuthenticate = true,
CookieContainer = cookieContainer,
UseCookies = true,
UseDefaultCredentials = true,
};
return clientHandler;
};
})
.WithAutomaticReconnect()
.Build();
_hubConnection.On<string, string, string, string>("ReceiveMessage", (userName, from, to, message) =>
{
if (user.Email == to || user.Id == from)
{
messages.Add(new Message()
{
Id = Guid.NewGuid().ToString(),
MessageText = message,
Chat = user.Id == from ? "sender" : "receive",
UserName = user.Id == from ? "You" : userName
});
StateHasChanged();
}
});
await _hubConnection.StartAsync();
}
public async void Send()
{
if (MessageBox.Value != "" && SendTo.Value != "")
{
var userName = user.DisplayName;
var to = SendTo.Value;
var message = MessageBox.Value;
var from = user.Id;
_hubConnection.SendAsync("SendMessage", userName, from, to, message);
}
}
public bool IsConnected => _hubConnection.State == HubConnectionState.Connected;
}
The issue is with authentication on azure platform. As you used manually giving cookies it worked fine on local, and when it comes to Azure platform, we need to provide authentication.
Follow the below link for support.
https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-invalid-json?pivots=dotnet-6-0
https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-tutorial-build-blazor-server-chat-app
HttpContextAccessor.HttpContext is where the problem is.
It works on your local (IIS Express), but it does not work when the application is deployed to Azure (or IIS).
I posted a solution here: Solution: Custom SignalR Endpoints (Hubs) in a Blazor Server Application using Azure B2C When Deployed to Azure
Basically:
Grab all the Cookies at this point and put them in a collection of Cookies so they can be passed to the app.razor control.
<body>
#{
var CookieCollection = HttpContext.Request.Cookies;
Dictionary<string, string> Cookies = new Dictionary<string, string>();
foreach (var cookie in CookieCollection)
{
Cookies.Add(cookie.Key, cookie.Value);
}
}
<component type="typeof(App)" render-mode="ServerPrerendered" param-Cookies="Cookies" />
Set them as a CascadingValue that will be passed to all other Blazor controls.
Retrieve the collection of Cookies as a CascadingParameter and use those Cookies to manually set the Header and Cookies when creating the SignalR client.
hubConnection = new HubConnectionBuilder()
.WithUrl(Navigation.ToAbsoluteUri("/chathub"), options =>
{
options.UseDefaultCredentials = true;
var cookieCount = Cookies.Count();
var cookieContainer = new CookieContainer(cookieCount);
foreach (var cookie in Cookies)
cookieContainer.Add(new Cookie(
cookie.Key,
WebUtility.UrlEncode(cookie.Value),
path: "/",
domain: Navigation.ToAbsoluteUri("/").Host));
options.Cookies = cookieContainer;
foreach (var header in Cookies)
options.Headers.Add(header.Key, header.Value);
options.HttpMessageHandlerFactory = (input) =>
{
var clientHandler = new HttpClientHandler
{
PreAuthenticate = true,
CookieContainer = cookieContainer,
UseCookies = true,
UseDefaultCredentials = true,
};
return clientHandler;
};
})
.WithAutomaticReconnect()
.Build();
hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
var encodedMsg = $"{user}: {message}";
messages.Add(encodedMsg);
InvokeAsync(StateHasChanged);
});
await hubConnection.StartAsync();

How to call an Azure Function App API with Easy-Auth Enables using Active Directory from a C# Client

I have an Azure Function App with Azure Active Directory configured but when I call if from my client I keep getting an Unauthorized response.
I have tried a couple different scenarios but nothing worked. Below is a snippet of the last bit of code that I tried.
///
var #params2 = new NameValueCollection
{
{"grant_type", "client_credentials"},
{"client_id", $"{ClientId}"},
{"client_secret", $"{ClientSecret}"},
{"username", userId},
{"resource", "https://management.azure.com/"}
};
var queryString2 = HttpUtility.ParseQueryString(string.Empty);
queryString2.Add(#params2);
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"grant_type", "client_credentials"},
{"client_id", ClientId},
{"client_secret", ClientSecret},
{"username", userId}
});
var authorityUri2 = $"{string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant).TrimEnd('/')}/oauth2/token";
//var authorityUri2 = $"https://login.microsoftonline.com/{Tenant}/v2.0/.well-known/openid-configuration";
var authUri2 = String.Format("{0}?{1}", authorityUri2, queryString2);
var client2 = new HttpClient();
var message = client2.PostAsync(authorityUri2, content).Result;
//var message = client2.GetAsync(authorityUri2).Result;
var response = message.Content.ReadAsStringAsync().Result;
dynamic values=null;
try
{
values = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
}
catch
{
values = response;
}
var AuthToken2 = values["access_token"];
client2.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthToken2);
HttpResponseMessage response2 = await client2.GetAsync(AppBaseAddress.TrimEnd('/') + "/api/AADIntegration");
if (response.IsSuccessStatusCode)
{
// Read the response and data-bind to the GridView to display To Do items.
string s = await response.Content.ReadAsStringAsync();
log.LogInformation($"Success while getting / api / AADIntegration : {s}");
return (ActionResult)new OkObjectResult(s);
}
else
{
string failureDescription = await response.Content.ReadAsStringAsync();
log.LogInformation($"An error occurred while getting / api / AADIntegration : {response.ReasonPhrase}\n {failureDescription}");
return (ActionResult)new OkObjectResult(failureDescription);
}
Data should returned from the Function App.
For client_credentials grant flow your code seems little different. Here I am giving you exact sample for azure function. Just plug and play :))
Example contains:
How would you get token using client_credentials flow
Getting user list From Azure Active Directory tenant using above
token
Access Token Class:
public class AccessTokenClass
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string resource { get; set; }
public string scope { get; set; }
public string access_token { get; set; }
}
Reference To Add:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Collections.Generic;
using System.Net.Http.Headers;
Azure Function Body:
public static class FunctionGetUserList
{
[FunctionName("FunctionGetUserList")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
try
{
log.LogInformation("C# HTTP trigger function processed a request.");
//Token Request endpoint Just replace yourTennantId/Name
string tokenUrl = $"https://login.microsoftonline.com/yourTennantId/Name.onmicrosoft.com/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "b603c7bead87-Your_client_id-e6921e61f925",
["client_secret"] = "Vxf1SluKbgu4P-Your_client_Secret-F0Nf3wE5oGl/2XDSeZ=",
["resource"] = "https://graph.microsoft.com"
});
dynamic json;
AccessTokenClass results = new AccessTokenClass();
HttpClient client = new HttpClient();
var tokenResponse = await client.SendAsync(tokenRequest);
json = await tokenResponse.Content.ReadAsStringAsync();
results = JsonConvert.DeserializeObject<AccessTokenClass>(json);
var accessToken = results.access_token;
//Create Request To Server
using (HttpClient clientNew = new HttpClient())
{
//Pass Token on header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Get Data from API
var requestToAzureEndpoint = await client.GetAsync("https://graph.microsoft.com/v1.0/users");
if (requestToAzureEndpoint.IsSuccessStatusCode)
{
var result_string = await requestToAzureEndpoint.Content.ReadAsStringAsync();
dynamic responseResults = JsonConvert.DeserializeObject<dynamic>(result_string);
return new OkObjectResult(responseResults);
}
else
{
var result_string = await requestToAzureEndpoint.Content.ReadAsStringAsync();
return new OkObjectResult(result_string);
}
}
}
catch (Exception ex)
{
return new OkObjectResult(ex.Message);
}
}
}
Point To Remember
For Azure Active Directory List users access make sure you have following permission:
User.Read.All
Permission Type: Application
You can check here. See the screen shot for better understanding; make sure you have clicked "Grant admin consent for yourTenant" after adding permission.
Note: This is how you can access Azure Active Directory Token using Azure Function after that how to access resource using that token to a specific API endpoint efficiently.
Are you sure you have properly implemented this properly? It looks like a few of your parameters are wrong for the client credential flow. Please double check that you are properly following the client credential flow.
The client credential grant flow is documented here : https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
But for more information on getting this properly working in your function app, please refer to the blog below for more information/help on implementing this.
https://blogs.msdn.microsoft.com/ben/2018/11/07/client-app-calling-azure-function-with-aad/
The value of resource is not correct.
Replace {"resource", "https://management.azure.com/"} with {"resource", $"{ClientId}"}

Call ServiceStack API Programmatically

What are the best ways to call a servicestack API from asp.net website. Service is running in IIS.
All the methods inside the service stack require authentication first.
I tried with JsonServiceClient and HttpWebRequest. First time when I authenticate, service gives me cookies
ss-id and ss-pid and I store in cookies collection. Now when I request another method It says, You are not authorised.
The problem is, in the second request Cookies are not maintained. However if you test the service from browser it self. It do create cookies first during Authorization and in second request, It gives you proper response.
Below is my code. With JsonServiceClient and HttpWebRequest
[HttpPost]
public ActionResult Index(Login loginModel)
{
#region ServiceStack Call
HttpCookie ck;
string baseUrl = "http://192.168.1.101";
var client = new JsonServiceClient(baseUrl);
var authResponse = client.Send<AuthenticateResponse>(new Authenticate
{
UserName = loginModel.UserName,
Password = loginModel.Password,
RememberMe = true
});
foreach (System.Net.Cookie cookie in client.CookieContainer.GetCookies(new Uri(baseUrl)))
{
if (cookie.Name == "ss-id")
{
ck = new HttpCookie(cookie.Name);
ck.Value = cookie.Value;
ck.Expires.AddDays(1); //Check when to expire the cookie
Response.Cookies.Add(ck);
}
}
}
Below Code with HttpWebRequest
protected string CallToApi(string baseUrl, bool createCookie)
{
CookieContainer cc = new CookieContainer();
System.Uri uri = new Uri(baseUrl);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = #"application/json; charset=utf-8";
request.Timeout = 200000;
request.Accept = "application/json";
request.CookieContainer = new CookieContainer();
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8);
if (reader != null)
{
if (createCookie)
{
//Create Cookies
}
}
return reader.ReadToEnd();
}
}
catch (WebException ex)
{
throw ex;
}
}
How to give call to second method?
http://192.168.1.101/api/teamleaders URL
When calling this Url, Can I persist my cookies? or there must be out of the box in ServiceStack itself.
The JsonServiceClient should persist cookies. I've used the following code (with the default CredentialsAuthProvider) successfully:
var client = new JsonServiceClient(baseUri);
var authResponse = client.Post(new Auth
{
provider = CredentialsAuthProvider.Name,
UserName = "username",
Password = "password",
RememberMe = true
});
Note: this is with version 3.9.71, NOT the new v4 stack which I haven't yet had the opportunity to upgrade to. The same 'should' work with a custom auth provider inheriting from CredentialsAuthProvider.

Return a custom auth response object from ServiceStack authentication

Is it possible to return a custom auth response? I already have my own custom authentication provider that inherits from CredentialsAuthProvider.
I want to return the session expiry date in the response, so that the client knows exactly when their server session will expire:
{
"sessionId": "bG27SdxbRkqJqU6xv/gvBw==",
"userName": "joe.bloggs#letmein.com",
"sessionExpires": "2013-04-29T03:27:14.0000000",
"responseStatus": {}
}
I can override the Authenticate method like so:
public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request)
{
// get base response
var response = base.Authenticate(authService, session, request);
// grab the session
var customSession = authService.GetSession() as CustomUserSession;
// if response can be cast and customSession exists
if (response is AuthResponse && customSession != null)
{
// cast
var authResponse = response as AuthResponse;
// build custom response
var customAuthResponse = new CustomAuthResponse
{
ReferrerUrl = authResponse.ReferrerUrl,
SessionExpiry = customSession.SessionExpires,
SessionId = authResponse.SessionId,
ResponseStatus = authResponse.ResponseStatus,
UserName = authResponse.UserName
};
return customAuthResponse;
}
// return the standard response
return response;
}
This works fine, except in the case where the session already is active. In that case, the AuthService Post method checks for a valid session and automatically returns a standard AuthResponse, and there is no obvious way to override it:
var alreadyAuthenticated = response == null;
response = response ?? new AuthResponse {
UserName = session.UserAuthName,
SessionId = session.Id,
ReferrerUrl = referrerUrl,
};
Following Paaschpa's ideas below, the following forces re-auth to always be re-authenticated, but it seems like there could be risks involved in leaving multiple active sessions open:
public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null)
{
// force re-authentication. Not great, but no other obvious way to do this
if (request != null)
{
return false; // auth or re-auth calls
}
return base.IsAuthorized(session, tokens, request);
}
Can anyone think of a better way to do this? I could implement my own AuthenticationService, but I'm not sure how I would override the AuthFeature?
If I understand correctly, you want to return a custom response after a user authenticates against '/auth/credentials'. Since you already have your own CredentialsAuthProvider I think you could just override Authenticate and return your own response.
Subclass of CredentialsAuthProvider
public class MyCredentialsAuthProvider : CredentialsAuthProvider
{
public override object Authenticate(ServiceStack.ServiceInterface.IServiceBase authService, IAuthSession session, Auth request)
{
//let normal authentication happen
var authResponse = (AuthResponse)base.Authenticate(authService, session, request);
//return your own class, but take neccessary data from AuthResponse
return new
{
UserName = authResponse.UserName,
SessionId = authResponse.SessionId,
ReferrerUrl = authResponse.ReferrerUrl,
SessionExpires = DateTime.Now
};
}
}

ServiceStack - Custom CredentialsAuthProvider within .Net MVC app

I am attempting to authenticate against MVC and ServiceStack following the example here - https://github.com/ServiceStack/ServiceStack.UseCases/tree/master/CustomAuthenticationMvc.
My issue is that I am unable to authenticate successfully against ServiceStack on my initial request to Account/LogOn.
ServiceStack related code in LogOn method of AccountController:
var apiAuthService = AppHostBase.Resolve<AuthService>();
apiAuthService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var apiResponse = apiAuthService.Authenticate(new Auth
{
UserName = model.UserName,
Password = model.Password,
RememberMe = false
});
I have a custom Authentication Provider that subclasses CredentialsAuthProvider. I Configure as follows in the AppHost class:
var appSettings = new AppSettings();
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new ActiveDirectoryAuthProvider(),
}));
public override bool TryAuthenticate(ServiceStack.ServiceInterface.IServiceBase authService, string userName, string password)
{
//class to authenticate against ActiveDirectory
var adAuthentication = new ActiveDirectoryAuthenticationService();
if (!adAuthentication.Authenticate(userName, password))
return false;
var session = (CustomUserSession)authService.GetSession(false);
session.IsAuthenticated = true;
session.UserAuthId = session.UserAuthName;
authService.SaveSession(session, SessionExpiry);
return true;
}
I think my issue is that session.Id is null at this point and saving the session persists 'urn:iauthsession:' to the 'SessionCache'. However, I'm not sure how to correctly populate session.Id. Also, this may or may not be an issue, but the initial LogOn request is to Account/Logon which is handled by MVC. So, there is no request to ServiceStack prior to the AuthService.Authenticate() call in the AccountController.
A possible solution I came up with has been added below in my subclass of CredentialsAuthProvider.
public override bool TryAuthenticate(ServiceStack.ServiceInterface.IServiceBase authService, string userName, string password)
{
//class to authenticate against ActiveDirectory
var adAuthentication = new ActiveDirectoryAuthenticationService();
if (!adAuthentication.Authenticate(userName, password))
return false;
var session = (CustomUserSession)authService.GetSession(false);
//A possible solution???
if(session.Id == null)
{
var req = authService.RequestContext.Get<IHttpRequest>();
var sessId = HttpContext.Current.Response.ToResponse().CreateSessionIds(req);
session.Id = sessId;
req.SetItem(SessionFeature.SessionId, sessId);
}
//end possible solution
session.IsAuthenticated = true;
session.UserAuthId = session.UserAuthName;
authService.SaveSession(session, SessionExpiry);
return true;
}
Is there a configuration or call I'm missing to 'wire up' ServiceStack Authentication within MVC?
Thanks.
The only thing I am doing in my TryAuthenticate is validating the user name, password and returning true if valid.
I have another override method called OnAuthenticated where I am saving the session information. OnAuthenticated passes the Auth Service and the Session as parameter so you only have to:
public override void OnAuthenticated(IServiceBase authService, IAuthSession session,.....
{
session.IsAuthenticated = true;
session.....
authService.SaveSession(session, SessionExpiry);
}
This seems to store my session information as long as I registered the ICacheClient.

Resources