How do Azure TokenCredentials support CAE like direct MSAL does in re-requesting an auth token with a claims challenge? - msal

Using MSAL directly, you end up adding the following to support CAE, so when an API call that used a _clientApp-obtained bearer token on it fails with 401 and has certain header info sent back which identifies that there is a claims challenge to re-process the getting of the auth token with, you then do so with something like this:
Created the auth client indicating you support CAE (in getting the initial auth token)
_clientApp = ConfidentialClientApplicationBuilder.Create(App.ClientId)
.WithDefaultRedirectUri()
.WithAuthority(authority)
.WithClientCapabilities(new [] {"cp1"}) // CAE-enabled
.Build();
Re-request an auth token in light of the claims challenge info
authResult = await _clientApp.AcquireTokenSilent(scopes, firstAccount)
.WithClaims(claimChallenge) // CAE-enabled
.ExecuteAsync()
.ConfigureAwait(false);
So ... how do you do the above two things when using a TokenCredential world, and not MSAL directly? Even though TokenCredential impls (at least those shipped by MS) internally do use CCAs and MSAL to do the job, they don't appear to expose a way to do this.
Hence my question:
How do you use a TokenCredential to re-request a claims-challenged auth token?

Related

How to silently renew Id Token using AddMicrosoftIdentityWebAppAuthentication to Call Downstream API

I am trying to implement the BFF-Gateway pattern (no tokens in the browser) to be used with a React SPA. The BFF is using AddMicrosoftIdentityWebAppAuthentication to handle login and issue a cookie to the SPA. And it is using YARP to proxy api requests to a downstream api. I'm using Azure B2C. Everything works perfectly until the BFF id_token expires in 1 hour. At that point, fetching the downstream api access token via GetAccessTokenForUserAsync (which is called in a piece of middleware) fails:
var scope = _configuration["CallApi:ScopeForAccessToken"];
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { scope });
ctx.Request.Headers.Add("Authorization", "Bearer " + accessToken);
Exception:
IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent.
ResponseBody: {"error":"invalid_grant","error_description":"AADB2C90085: The service has encountered an internal error. Please reauthenticate and try again.\r\nCorrelation ID: 622d6bd6-d06e-4142-86f2-b30a7a17b3b5\r\nTimestamp: 2022-11-25 09:31:23Z\r\n"}
This is effectively the same as Call Downstream API Without The Helper Class example and this sample, except that I'm acquiring the access token in middleware, not a controller, so the downstream YARP requests contain the access token. BTW I get the same error if I do this inside a controller per this example. And I see no soluton to this in the sample.
There is a similar question here which references the sample referenced above, but for the B2C sample I see no solution to this problem.
I also found this sample and this explanation. But this uses Microsoft.Owin to configure auth, not AddMicrosoftIdentityWebAppAuthentication. This looks promising, but is a departure from most examples I see that use Microsoft.Identity.Web.
Can you please point to the correct soluton? I need call to be able to call _tokenAcquisition.GetAccessTokenForUserAsync after the id token expires without asking the user to reauthenticate and/or the SPA to having to reload.
At the moment I am handling this issue in the SPA by catching the exception from MSAL and redirecting back to the login endpoint in the BFF which initiates the challenge. This gets me a new id_token and cookie, but this is just a temp workaround as it's very disruptive to user to be redirected away from the SPA.

Add claims to security.oauth2.jwt.Jwt

I have a SpringBoot OAuth2 Client and ResourceServer. My AuthorizationServer is Okta.
Now suppose that in a certain moment I want to add a claim to my token, for Example:
#GetMapping("/addIdUser")
public ResponseEntity<String> addUser(#AuthenticationPrincipal Jwt jwt) {
// here I want to add a claim to my Jwt, the token
// should return to the frontend and when I resend back to my resourceserver
// it should be validated again
return new ResponseEntity<String>(token, HttpStatus.OK);
}
I have read tons of docs of TokenEnhencer and TokenConverter but it not seems to be the solution I looking for.
Can I do something like this?
Seems like you want to authorize based on domain specific claims, and there are two main options here:
Get extra claims at the time of token issuance - Okta needs to either call an API or do a database lookup - this is the preferred option but not always possible
Look up claims in the resource server when an access token is first received, then cache them for subsequent requests with the same access token
Leave the Okta issued token alone in the client, then adopt one of the above two approaches in the API. Out of interest, here is a Spring Boot API of mine that uses a library based approach to OAuth handling and implements both approaches:
Standard Authorizer
Claims Caching Authorizer

Bot DirectLine Token Distribute Issue

based on this Bot DirectLine Authentication,
If you plan to distribute the token to clients and want them to initiate the conversation, use the Generate Token operation.
Does this mean we can generate token from backend using Secret and distribute the token to the client for starting a conversation?
To test it, I wrote these:
Backend: #Azure Function
[FunctionName("XXXXX")]
public static async Task<object> RunAsync([HttpTrigger(Route = "XXXXX")] HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook was triggered!");
var tokenResponse = await new DirectLineClient(directLineSecret).Tokens.GenerateTokenForNewConversationAsync();
return req.CreateResponse(HttpStatusCode.OK, tokenResponse.Token);
}
and
Client #UWP
// token from Backend
directLineClient = new DirectLineClient(token);
var conversation = directLineClient.Conversations.StartConversation();
weird thing is the variable conversation is null.
When I put the Generate Token code of Backend to Client, it works that the variable conversation is a valid object.
my question is: can we put the Generate Token in backend and distribute token to clients?
my question is: can we put the Generate Token in backend and distribute token to clients?
Of course, if you do not want to expose/share Direct line secret publicly, you can generate Token in backend service and distribute the token to clients and let them to initiate the conversation.
Note: please make sure the Direct Line token generated by your http triggered function is not expired when you use it in your DirectLine Client.
I do a test with DirectLineClient of Direct Line Bot Sample, and modify the code to accept the Direct Line token. If I provide a Direct Line token that is expired, starting conversation will fail.
The problem is that the backend should return token as text media type. much appreciated for your feedback and reminding.
return req.CreateResponse(HttpStatusCode.OK, tokenResponse.Token, "text/plain");

Authenticating an API request with a Token

Suppose I make an API request to the following URL:
https://myapi.com/data
This is an API I built and have full control over.
I would like to limit access to this API to only the apps I authorize.
I see many services will provide you with an API key which you can append to your URL to give you access.
Suppose I have:
https://myapi.com/data?key=a6reallly7long2string9of0numbers2and4letters
Then on the backend I have something like:
class REST {
public $ACCESS_TOKEN = 'a6reallly7long2string9of0numbers2and4letters',
public function Auth($token){
if($token===$this->ACCESS_TOKEN) return true;
return false;
}
}
If the values match, I allow access.
But all someone would have to do is look at the request the app is making on the client side and they have the token.
Even if I encrypt the token or use one-way hashing, they'll still have the value that decrypts to the correct result.
How does one approach good authentication via URL token for an API?
I would like to limit access to this API to only the apps I authorize.
What are you looking for is "access authorization". Indeed, an access token seems to be a good way, but there are some aspects missing
** Authorization header **
By default the token should be sent as an HTTP header (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) not in the url
Commonly used Authorization headers types are Basic (for basic authentication) and Bearer (for OAuth authentication and authorization)
The token should not be a hardcoded constant. It should be created/generated based on the application (and optionally user) authentication. And still better if the token is temporary
Now you can ask - how can an application keep its credentials secret? Each application can have their own server services (end user should.not access application credentials) or pure web application should be comtrolled by the CORS headers
Just search for OAuth 2.0 protocol and JWT token (jwt should be self-contained and signed).
IMHO the URL token may be an option when there is no other alternative, as URL is often cached, resent, logged,...
** API Manager **
If you have resources (server) to do so, you can deploy an API manager (there are open source, commercial or cloud options, just search for some). API manager will handle the application enrollment, authorization and enforcement.

WP7 C# Retrieve access tokens of Google OAuth 2.0 request

I followed this guide to use Google OAuth 2.0 authorization, but I can't understand how to implement request to retrieve access and refresh token in my Application. The code, as that guide say, is the current:
// Request an access token
OAuthAuthorization authorization = new OAuthAuthorization(
"https://accounts.google.com/o/oauth2/auth",
"https://accounts.google.com/o/oauth2/token");
TokenPair tokenPair = await authorization.Authorize(
ClientId,
ClientSecret,
new string[] {GoogleScopes.CloudPrint, GoogleScopes.Gmail});
// Request a new access token using the refresh token (when the access token was expired)
TokenPair refreshTokenPair = await authorization.RefreshAccessToken(
ClientId,
ClientSecret,
tokenPair.RefreshToken);
Where and how can I call this function in a generic Windows Phone application?
(Sorry if there this question it's duplicate, but I try to search and I only find as answers links to generic Google Apis guide)
You call it when it's necessary (when you need to get tokens). After that use official Google libraries to get access to API and provide them data from TokenPair. Plus, remember to get this (https://github.com/pieterderycke/MobileOAuth/blob/master/MobileOAuth/GoogleScopes.cs) in your project, so you can use GoogleScopes.

Resources