How to force AD FS 3.0 (Windows 2012 R2) to send nbf (not before) in jwt - claims-based-identity

I am trying to receive JWT token from oauth2 endpoint of ADFS in my single page application. I succesfully received code from oauth2 endpoint. After ajax POST request i received access_token and refresh_token. But when i look to access_token i have there only these claims:
{
"aud": "https://localhost/",
"iss": "http://fs.development.org/adfs/services/trust",
"iat": 1438015081,
"exp": 1438018681,
"email": "Test.User#development.org",
"role": "Domain Users",
"unique_name": "Test.User",
"primarysid": "S-x-x-xx-xxxxxxxxx-xxxxxxxxx-xxxxxxxxxx-xxxx",
"upn": "test.user#development.org",
"auth_time": "2015-07-27T16:40:01.636Z",
"authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
"ver": "1.0",
"appid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
As you can see i didn't receive nbf claim from AD FS. I cannot find it in configuration of my relying party trust. I tried to set property NotBeforeSkew to two minutes and TokenLifetime to 60 minutes on my relying party in hope that AD FS start sending nbf claim. But i was wrong, nothing helps in any way.
So my question is this. It is possible to force from my application or from ad fs server to send nbf claim?
Maybe it is just matter of configuration but i wasn't able to deduce from documentation how this claim can be configured.

The only way I have found to fix this is add a custom claim rule to ADFS. This feels like a bit of a hack, but I simply set 'nbf' to zero and then any consumer will at least not complain about a lack of this property. Although 'nbf' is in fact optional Sharepoint 2013 seems to deem it mandatory when using OAuth which was the original reason in my case that I needed to supply some value. Here is my custom claim rule for anyone struggling with this:
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(Type = "nbf", Value = "0");

Related

how to handle/manage a lot of permissions in access-token? what's the best approach?

I'm getting a "Request header is too long" error when i was trying to access my API and send token in header. How we can manage a permissions in access-token because i have a lot of permissions in access-token it's approximately 15kb in size.
I know it's not recommended to store permissions in access-token then what's the best approach to authenticate and authorize the users on API side?
We are getting all the permissions in access token but now permissions are getting large as we have lot of modules. What is the other way to access user permissions in asp.net core API instead of keeping it in access token?
{
"roles": [
"Admin"
],
"iss": "Issuer",
"sub": "sub",
"aud": [
"https://example.com/api",
"https://example.com/userinfo"
],
"iat": 1666198659,
"exp": 1666205859,
"azp": "azp",
"scope": "openid profile email offline_access",
"org_id": "company1",
"permissions": [
"permission.1",
"permission.2",
........
"permission.150",
]
}
This could be a solution: https://fga.dev/. There's also the open source version: https://openfga.dev/
Basically, since every user has a lot of permissions, you don't store them in the token anymore; you can call this service which stores them for you.
Disclaimer: I am part of the team building this solution :)
You have two options.
You can try to shorten the permissions down using something like the approach here. There are lots of other similar questions with similar approaches. However, know that you limit your number of permissions based on what you inherit from so this may or may not work. You can stick a string into the JWT with each char working as a flag for a permission. This comes with more downsides, namely keeping the data up-to-date.
You setup a remote system for authorization. Something like Policy Server from Duende. This means no authorization data in the JWT. For instance you can make a simple http call to your identity server from your api/client and have the identity server evaluate if the user can do what they want to.
The latter seems right for your scenario because of your large amounts of permissions. It comes with overhead but there isn't really an alternative. https://github.com/Perustaja/PermissionServerDemo is an example that uses the built in ASP.NET Core authorization evaluation along with gRPC for the network calls. You can make something leaner and simpler that basically does the same thing if you don't want a lot of infrastructure.

Authenticating requests to an API based on tokens that originate from a different API

I'm building an API (API 1) that acts as an extension of another API (API 2).
API 1 essentially provides additional functionality that does not exist in API 2.
API 2 contains some core methods that are called by API 1, and also happens to serve as the source of truth for user credentials.
What I'm thinking of doing is this: every time a client authenticates with API 1 (i.e. login), I want to "relay" that call to API 2 to retrieve a bearer token and then pass that back to the requesting client. From that point on, I'd like API 1 to be able to accept/validate that bearer token (which originated from API 2) for any subsequent calls to its own controller methods. How would API 1 actually validate the token if it didn't actually create it?
My first thought is to write a custom handler somewhere in API 1 that somehow asks API 2 to validate the incoming token. Does this approach make sense given what I've described above? If so, how do I get started? I don't know too much about implementing custom OAuth or JWT inside a .NET 5 API, so I need pointers on what steps I'd need to take to implement this.
I apologize if this question is too ambiguous; I've been trying to wrap my head around this for days now and am not sure where to even begin researching a solution, much less implement it.
You definitely can validate the token issued by API2 in API1. If API2 is some commercial product, like e.g. auth0, all you need to do in API1 (assuming it's a .net core app) is to set up the validation URL. API1-app will get all the validation info from there automatically:
services.AddAuthentication().AddJwtBearer("myscheme", options =>
{
// auth0 authentication
options.Audience = configuration["Auth0Settings:ApiIdentifier"];
options.Authority = configuration["Auth0Settings:Domain"];
})
If API2 is your own app, you likely didn't implement all the oauth stuff with discovery URLs etc., but you should know the secret and you can validate the token in API1 yourself:
.AddJwtBearer("myscheme", options =>
{
var jwks = GetJwksKeyFromWhereeverYouStoreThem();
var audience = configuration["Custom:Audience"];
var domain = configuration["Custom:Domain"];
options.Audience = audience;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = domain,
ValidateAudience = true,
ValidAudience = audience,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = jwks.Keys,
RequireSignedTokens = true,
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
ValidAlgorithms = new[] { SecurityAlgorithms.YourAlgorithm, },
};
});
And yes, you could proxy the call from API1 to API2 in order to get the token. You would need however to authenticate your API1-app against your API2-app. Depending on what your API2 is, it could involve special grants to issue tokens on behalf of the end-user (you will be passing username and password to API2).
Having said all this, proxying the authentication IMHO is not a good idea. You potentially lose some security already implemented by the API2 by passing your credentials from API1. In the example of auth0 it involves a password grant, which should be used only by trusted applications. Your client should authenticate against the service that issues the bearer. It may seem good at first to proxy the call, but you loose more than you win (all the changes in API2 will influence your API1, you don't get new security features etc. etc.).
You could also add an API gateway to your setup, implemented e.g. with Ocelot. This will take care of authentication and hide your auth logic from your clients. This is IMHO the best way to go, but is often out of scope. Without a gateway the best setup is when one service issues the tokens and validates them and all other services use these tokens and validate them against the first service.

Should Name Claim remain omitted in JWT Access Token with IdentityServer4 (using Identity) and ASP.Net Core API?

While configuring my IdentityServer4 (using Identity) resource owner grant flow with an asp.net core API backend, I got to thinking that perhaps the "Name" claim should remain omitted in the JWT access token for user security? This claim is not available with out of the box behavior of IS4.
Previously, I had been adding in the "Name" claim for the access token in my IS4 Config.cs file as follows:
var claims = new List<string>
{
JwtClaimTypes.Name
};
return new List<ApiResource>
{
new ApiResource("api1", "Auth API", claims)
};
I was doing this because it allows a straightforward approach to get a logged in user's ClaimsPrincipal.Identity.Name for user look up inside a Controller action.
var name = User.Identity.Name;
var user = await _userManager.FindByNameAsync(name);
However, IS4 access tokens (when using Identity) include the user's GUID id in the "Sub" claim. With this, we can also look up a user using the following:
var userId = User.Claims.FirstOrDefault(u => u.Type == "sub").Value;
var user = await _userManager.FindByIdAsync(userId);
I know there is slightly more processing with the LINQ query (hardly anything tbh), but I was thinking it might be of worth to protect a user's username (email address in my situation) if an access token ever fell into the wrong hands. Especially since JWT's are so easy to decode with the likes of jwt.io.
Do you guys agree or disagree? Or am I looking at this the wrong way and missing something?
JWT usually contain the public data and it is self-contained. i.e. You don't need to communicate with a backend server to construct user's identity. You should prevent the token fell into wrong hand by using https. Also, you should balance your token validity window(usability vs security) and use a nonce for maximizing the security.
I don't think 'name' should be omitted from claim collection. A valid use-case for what you are doing is that you need to make sure that changes to your user store immediately reflect in your web API. In the case of a self-contained token, if you change the 'name' in the data store, the user will not see that change until he was issued a new token. In this case use of a 'reference token' might be a good option.
Also, It looks like you are directly accessing user store from the web API. While you might have valid reasoning behind this, Idea of using token based authentication is to delegate authentication to external party(Identity Server). So common pattern is to
Include every public data that you require in the web API in the
access token.
If token getting too big, include a subset of claims in the token and query user info endpoint when required.
Use reference tokens if you have valid reasons to do so. But this will affect the performance as it will require back channel communication with identity server.

Access to Outlook RestAPI from an Outlook web Add-in

I developed an Outlook Web Add-in that is working fine. It's a Taskpane that is available in compose mode of appointments and that collects event's data, adds a few ones and send that all to an API somewhere.
What I would like to do now is to subscribe the authenticated user to the Outlook Rest API in order to get notified when the event is deleted.
The subscription call should look like this one:
POST https://outlook.office.com/api/v2.0/me/subscriptions HTTP/1.1
Content-Type: application/json
{
#odata.type:"#Microsoft.OutlookServices.PushSubscription",
Resource: "https://outlook.office.com/api/v2.0/me/events",
NotificationURL: "https://myNotifAPI.azurewebsites.net/api/send/myNotifyClient",
ChangeType: "Deleted",
ClientState: "blabla"
}
I know I need to provide a valid Authentication Bearer Token when posting to the subscriptions URL so I tried to call this method in my Add-In:
_mailbox = Office.context.mailbox;
_mailbox.getUserIdentityTokenAsync(getUserIdentityTokenCallback);
In the function getUserIdentityTokenAsync, I call a WebApi Controller that validates my token and send it back to the Add-In:
AppIdentityToken token = (AppIdentityToken)AuthToken.Parse(rawToken);
token.Validate(new Uri(request.AudienceUrl));
return token;
I tried to use that token to Post to https://outlook.office.com/api/v2.0/me/subscriptions (using Postman) but I got a 401 saying:
reason="The audience claim value is invalid '<MyAddInURL>'.";error_category="invalid_resource"
Is it the right Token to use in that particular case or do I need to get another one? Any advices would be appreciated!
-- EDIT --
As suggested by #benoit-patra I tried to get a token using getCallbackTokenAsync instead of getUserIdentityTokenAsync but when I called https://outlook.office.com/api/v2.0/me/subscriptions I did receive a 403 :
"error": {
"code": "ErrorAccessDenied",
"message": "The api you are trying to access does not support item scoped OAuth."
}
As requested by #benoit-patra here's the Token content :
{
"nameid": "9d643d8c-b301-4fe1-83f7-bf41b1749379#57bcd3d9-685a-4c41-8c7d-xxxxxx",
"ver": "Exchange.Callback.V1",
"appctxsender": "https://localhost:44444/NewAppointment.html#57bcd3d9-685a-4c41-8c7d-xxxxxx",
"appctx": {
"oid": "3a8a4f92-a010-40bd-a093-xxxxxx",
"puid": "10033FFF9xxxxx",
"smtp": "max#xxxx.onmicrosoft.com",
"upn": "max#xxxx.onmicrosoft.com",
"scope": "ParentItemId:AAMkADE4NTk2MDNjLTI4NGEtNDZkNS1hMzg4LTE3MzI2NGJhZWRkZQBGAAAAAAD+YYA7CnMtRZsrwJ7l6m44BwCcSer9F+cXSrWNauuHQlZ7AAAAAAENAACcSer9F+cXSrWNaxxxxxxxx"
},
"iss": "00000002-0000-0ff1-ce00-000000000000#57bcd3d9-685a-4c41-8c7d-xxxxx",
"aud": "00000002-0000-0ff1-ce00-000000000000/outlook.office365.com#57bcd3d9-685a-4c41-8c7d-xxxx",
"exp": 1487087672,
"nbf": 1487087372
}
The previous answer is right, the error is because you are getting an item scoped token. Because previously Callback tokens only allowed a caller to call GetItem and GetItemAttachment REST APIs. We are making changes to the callback token so that clients can call REST of the APIs as well. The requirement is first you should have readWriteMailBox permission. Second get a REST callback token by providing isRest=true, like below
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (result))
The resulting token will have Mail.ReadWrite, Calendar.ReadWrite, Contacts.ReadWrite, and Mail.Send Scopes.
That said the isRest parameter is only supported for outlook mobile client right now. The work to support it on OWA and Outlook is in progress and we expect to release it by March.
You should use getCallbackTokenAsync() this is the JWT that will give you the AccessToken that will help you authenticating for the Outlook REST API
https://dev.office.com/docs/add-ins/outlook/use-rest-api
For your case, following the documentation, I think you will need ReadWriteMailbox to have sufficient permissions to register web hooks with Outlook REST API.
NOTE: I tried this on my add-in, I changed the add-in permission to ReadWriteMailbox but the JWT token when inspected with JWT.io still has for scope:ParentId=<itemid> which I think won't work. Tell me if you have the same problem here.

When used Sub and Aud Claim of payload on a system with JSON Web Token

I'm conducting tests to understand and implement a system of user authorization through the use of JSON Web Token.
Looking for information about the configuration of a token arises me a couple of questions about the use of two Claim Payload, the Sub and Aud.
{
"iss": "www.miweb.com", // issuer
"iat": 1455550200, // time was issued
"exp": 1455559810, // expiration timestamp
"nbf": 1455550260, // not before
"jti": "31d6cfe0d16ae931b73c59d7e0c089c0", // unique identifier
"sub": "", // ¿subject?
"aud": "", // ¿?
"data": {/* attached data */}
}
From what I've observed is rarely used these two claim. My question then is:
What scenario can give use and for what purpose?
Thank you very much, greetings
Same written in Spanish StackOverflow question: https://es.stackoverflow.com/q/11786/5984
Ps: Sorry for the language, not domain.
Edited: Translation of comments in the code
The Subject ('sub') claim identifies the user or application (in case of client credentials flow) that was authenticated.
The Audience ('aud') claim indicates who the token is issued for.
Suppose my client application needs to call service A of behalf of user X.
Typically, my application would communicate with the authorization server to authenticate the user (for example using one of the OAuth2 grant flows) and request access to service X. The authorization server would authenticate the user and ask for consent.
If the user gives consent, the authorization server will issue a JWT token with a subject claim unique for user X and an audience claim indicating service A.