I am trying to call Exchange web services (EWS) end points from my WCF service using OAuth authentication.
I have registered the app on Azure portal and able to generate and authenticate it using access token.
My question is about how I can refresh the token in WCF service. It seems access token has an hour validity.
// Using Microsoft.Identity.Client 4.22.0
var cca = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["appId"])
.WithClientSecret(ConfigurationManager.AppSettings["clientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["tenantId"])
.Build();
// The permission scope required for EWS access
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
//Make the token request
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
Followed below link for this.
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
Thanks
In your WCF client you want to do something like How to add a custom HTTP header to every WCF call? so you have a piece of code that runs before any request is made that calls AcquireTokenForClient which should use the Token Application Cache (so it will either give you the current token if valid or acquire a new token if expired).
Related
I am having an application where Authentication is done using IdentityServer4 with Azure AD as an OpenID provider. IdentityServer4 is hosted in Azure App service. After successful authentication, I am able to get access token in Angular application. Access token is passed to .Net Core based RESTful API which is hosted in Azure Function 3.x.
In my Azure function I would like to get user info and other claims without hitting the end point "/connect/userinfo" of IdentityServer4.
Something similar to following for getting Claims would be helpful
[FunctionName("MyFunctionName")]
public static HttpResponseMessage Run(
[HttpTrigger(
AuthorizationLevel.Anonymous,
"get", "post",
Route = "MyFunctionName")]HttpRequestMessage req,
ILogger log,
ClaimsPrincipal claimsPrincipal)
{
// My function code here...
}
How do I get I user info and other claims in Azure function where Authentication is done by IdentityServer4 with Azure AD as OpenID provider
If you have a valid access token, then you can make a request on your own to the UserInfo endpoint to retrieve the remaining user details.
Read more about it here
The only option if you don't want to access the userinfo endpoint is to include the required data in the tokens directly. Here you need to do a trade-of between token size vs convenience. Then you get a really stateless system.
If you don't want to hit user info end point of Identity Server to get the user info and other claims, here is what needs to be done.
Add the claim info to the authorization token
Parse the authorization token and extract the user info and other claim information.
The downside of this approach is that the token size is increased but advantage is that you don't need hit userinfo end point which saves your http request(s). So there are trade offs between each approach.
Here is how you can add claims info while configuring your api in Identity Server. Typically this information resides in Config.cs if you have used Identity Server template
public static IEnumerable<ApiResource> GetApis()
{
var apiResourceList = new List<ApiResource>
{
new ApiResource(IdentityServerConstants.LocalApi.ScopeName)
{
UserClaims =
{
JwtClaimTypes.Email,
JwtClaimTypes.PhoneNumber,
JwtClaimTypes.GivenName,
JwtClaimTypes.FamilyName,
JwtClaimTypes.PreferredUserName
},
}
};
return apiResourceList;
}
For parsing and validating the token please follow the blog Manual token validation in Azure Function
This StackOverflow thread is also very useful.
I have a ASP.NET Core app that I'm using OIDC (Microsoft Azure AD) to authenticate users to my app. I have added a ton of APIs to the Registered Application in Azure AD including Dynamics. How can I access the access token in my middleware? I created a class for the sole purpose of communicating with Dynamics and would like to reuse the access token generated during authentication to my app. How and where do I get it from? I have tried all the usual suspects such as the following:
var accessToken = _httpContextAccessor.HttpContext.Request.Headers[HeaderNames.Authorization].ToString(); // null
and
var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; // null
Any suggestions?
To get access token for calling Dynamics API with the authenticated user context, application should get access token using OBO flow. MSAL.NET has method to do so.
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
You can refer this ASP.NET Core Sample and has the similar scenario that you are trying to achive.
I've got access_token from Azure Ad V2.0 endpoint to call Graph Api. But I have to do some actions in the api on behalf of user. So I need refresh_token to renew my access_token when it'll expire.
Is there any way to get Refresh token using MSAL in ASP .Net Core?
In microsoft documentaion they're telling it's possible to do by requesting /token endpoint. But I couldn't find how to do it using MSAL.
MSAL .NET does not expose the refresh token, but rather keeps it internal and handles all token refresh and caching logic on the app's behalf.
The docs you're referring to are referencing the protocol itself that MSAL is completing on your behalf. It goes to the /token endpoint with an authorization code (after the end user signs in), and is issued an Access and Refresh token. The Access Token is valid for 1 hour, and when it's expired, AcquireTokenSilent will automatically use the refresh token against the /token endpoint to get a new access token.
I got a bit topsy-turvy on this, as well. Explaining a bit more based on my understanding.
For context, OAuth 2.0 code grant flow mentions the following steps:
authorization, which returns auth_code
using auth_code, to fetch access_token (usually valid for 1 hr) and refresh_token
access_token is used to gain access to relevant resources
after access_token expires, refresh_token is used to get new access_token
MSAL.NET abstracts this concept of refresh_token via TokenCache.
There is an option to serialize TokenCache. See Token cache serialization in MSAL.NET. This is how to preserve sign-in info b/w desktop application sessions, and avoid those sign-in windows.
AcquireTokenSilentAsync is the process by which refresh_token is used to get new access_token, but, this is internally done. See AcquireTokenSilentAsync using a cached token for more details and other access patterns.
Hope this clarifies on why TokenCache is the 'new' refresh_token in MSAL.NET, and TokenCache is what you would need to serialize and save. There are libraries like Microsoft.Identity.Client.Extensions.Msal that aid in this.
TokenCache is basically a JSON object which is served as byte array when you call SerializeMsalV3(). When you convert byte array to string, you will see both access token and refresh token. Then you can make a HTTP request to \token endpoint with this refresh token and grant_type: "refresh_token" body parameters.
IConfidentialClientApplication capp =
ConfidentialClientApplicationBuilder.Create(myClientId)
.WithClientSecret(myclientSecret)
.Build();
capp.UserTokenCache.SetAfterAccess((TokenCacheNotificationArgs args) =>
{
exchangeTokenCacheV3Bytes = args.TokenCache.SerializeMsalV3();
string jsonString = System.Text.Encoding.UTF8.GetString(exchangeTokenCacheV3Bytes);
});
We have an environment with the following:
Standalone IdentityServer3 instance (issues reference tokens, not jwt)
ASP.NET WebAPI resource server
.NET client applications that authenticate against IdSvr (via resource owner flow)
...and now we'd like to start adding an OWIN-hosted web app that will use NancyFx to serve server-rendered pages as well as a couple AngularJS SPAs. This Nancy website will NOT host any APIs, but may consume data from our existing API. I'd like to add authentication in the OWIN pipeline to help secure our Angular applications from being sent down to users who don't have access.
This would be in contrast to sending down the SPA code, and having Angular determine if the user should see anything. In that case we've already exposed the javascript code base, and this we want to avoid.
I'm trying to understand how I should configure this Nancy site to authenticate users against IdentityServer using the implicit flow. I have implemented this authentication scheme in standalone SPAs before (where all authentication was handled by AngularJS code and tokens were stored in HTML5 local storage), but I'm a bit lost on how to properly tackle this within the OWIN pipeline.
I'm thinking that the OWIN cookie authentication middle-ware is the answer, but does that mean the following?
I need to redirect the user to IdentityServer (using the proper url arguments for implicit flow)?
IdentityServer will redirect the user back to my site on a successful login, so is that where I hook into the OWIN Authorization manager to set the appropriate cookie?
...or am I thinking about this all wrong?
For reference, I've read through the following posts, and they're very helpful but I'm not quite seeing the big picture with OWIN. I'm going to experiment with the UseOpenIdConnectAuthentication middle-ware next, but I would appreciate any guidance SO might have here.
http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/
https://github.com/IdentityServer/IdentityServer3/issues/487
Fundamentally, implementing OpenID Connect authentication in a Nancy app hosted via OWIN is really not different from implementing it in any MVC/Katana app (the Thinktecture team has a sample for this scenario: https://github.com/IdentityServer/IdentityServer3.Samples/tree/master/source/Clients/MVC%20OWIN%20Client)
You basically need 3 things: the cookie middleware, the OpenID Connect middleware and the Nancy middleware:
public class Startup {
public void Configuration(IAppBuilder app) {
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
AuthenticationMode = AuthenticationMode.Active,
// Set the address of your OpenID Connect server:
Authority = "http://localhost:54541/"
// Set your client identifier here:
ClientId = "myClient",
// Set the redirect_uri and post_logout_redirect_uri
// corresponding to your application:
RedirectUri = "http://localhost:56765/oidc",
PostLogoutRedirectUri = "http://localhost:56765/"
});
app.UseNancy(options => options.PerformPassThrough = context => context.Response.StatusCode == HttpStatusCode.NotFound);
}
}
If you're looking for a functional demo, you can take a look at https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy/Nancy.Client (note: it doesn't use IdentityServer3 for the OIDC server part but it shouldn't make any difference for the client app).
Following this post I have created a WCF client which:
Uses ADFS to authenticate users against AD.
Provides a SAML2 ticket to the caller.
Uses the supplied SAML2 ticket to call the WCF Service.
This is working great, however the next part of my problem is to extend this to use Azure ACS.
I added the RP to ACS, and changed the STS reference to point to ACS using Add STS Reference in Visual studio.
I have extended the Token.GetToken method, supplying the token into the following method:
public static SecurityToken GetToken(SecurityToken adfsToken, string appliesTo, string idpEndpointAddress, out RequestSecurityTokenResponse rsts)
{
WS2007HttpBinding binding = new WS2007HttpBinding();
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress(idpEndpointAddress));
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.ConfigureChannelFactory();
// Create issuance issuance and get security token
RequestSecurityToken requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
requestToken.AppliesTo = new EndpointAddress(appliesTo);
WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannelWithIssuedToken(adfsToken);
SecurityToken token = tokenClient.Issue(requestToken, out rsts);
return token;
}
To the following endpoint:
https://test.accesscontrol.windows.net/v2/wstrust/13/issuedtoken-symmetric
But I get the following exception:
Secure channel cannot be opened because security negotiation with the
remote endpoint has failed. This may be due to absent or incorrectly
specified EndpointIdentity in the EndpointAddress used to create the
channel. Please verify the EndpointIdentity specified or implied by
the EndpointAddress correctly identifies the remote endpoint.
With an inner exception of:
ACS10001: An error occurred while processing the SOAP header.
What do I need to configure in ACS to get this working with the token supplied by ADFS?
Do I need to use the token supplied by ACS, or can I use the one supplied by ADFS in the service? (It appears to be working..)
Take a look at the linked ACS sample, which seems to be doing exactly what you're asking.