I implemented the Identity Server using the stores against CosmosDb, the access token is very short compared to the id token, guess I'm missing some config or some interface to implement.
Access Token: -TPc90IVKUxMOxLLIZmQcCgGGkdRXf7207sfb_b1-7E
Id Token: eyJhbGciOiJSUzI1NiIsImtpZCI6InNOcnBNMlVrUEF0ajlZYzZFZGNaVWciLCJ0eXAiOiJKV1QifQ.eyJuYmYiOjE1ODQ5MDMyMjgsImV4cCI6MTU4NDkwMzUyOCwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NjAwMSIsImF1ZCI6Im12Y0NvZGVGbG93Q2xpZW50Iiwibm9uY2UiOiI2MzcyMDUwMDAyMDQyODgxNzQuWmpjMU9HSTVOVEF0WWpKbVpTMDBNMlJsTFRnelkyTXRaRFZoWmpSbFpUSXpZVEppWWpSa01tWTNZemd0TW1Nell5MDBabUk1TFRrMU9UTXRaamMyTTJRek1XTXpNbVF6IiwiaWF0IjoxNTg0OTAzMjI3LCJhdF9oYXNoIjoiWUM4OU1TTnVmZTVycEpZby14Y3l1QSIsInNfaGFzaCI6IkcwUmM0eDktTHRJN0pFZUdxQmtUN1EiLCJzaWQiOiJ0a3IwNGVNOG1UVS02dG96anNqTEdBIiwic3ViIjoic3VkaGVyc29uLnZAZ21haWwuY29tIiwiYXV0aF90aW1lIjoxNTg0OTAyNjYzLCJpZHAiOiJsb2NhbCIsImlkIjoiYjQ0YjRhMWItOGU1NS00OGUzLThkZjktYWUxNzhmZThkY2ZjIiwibmFtZSI6IlN1ZGhlcnNvbiBWZXRyaWNoZWx2YW4iLCJnaXZlbl9uYW1lIjoiU3VkaGVyc29uIiwiZmFtaWx5X25hbWUiOiJWZXRyaWNoZWx2YW4iLCJlbWFpbCI6InN1ZGhlcnNvbi52QGdtYWlsLmNvbSIsImFtciI6WyJwd2QiXX0.N9Xv7Uvgg5GlrB-9HPU3-WJffdP1z_400Rm2f246DPWEM7tDkBOtCUW_1Oo5GXURNgCJXmsQGvKelGUs8ysPzHS_t3faK-_57QHugubUqvDPqJgimHw8iJz-PFNKPS9hPI0Bnw889tNYJ7pnmTQH16PurF2Cgi2xB7p2Uc4SN1HLK5ed3usoMQ4Sxu08ONcy4MFy1b5JDjttSq4EA4xZGunQFNUNxOziroE6VTuvn7aOsEIKIiRuOyKOKQBct_H68Px3FUgwzTZ5ABD52_SzdzqoP1gZEZavSI6Wl5xIlRvaZqEyCUoGZ2TqFKSydRdZbARmSbFl1SfmAzyCwvYjHA
Just for summary:
The issue is solved by using reference token instead of JWT. Id Server 4 is writing grants to storage as reference token by default.
More details for reference token of identityserver4 ,please refer to https://identityserver4.readthedocs.io/en/latest/topics/reference_tokens.html
I started implementing IdentityServer4 against cosmosdb as persistence, referenceLink, had some error while writing grants to cosmos db, then I followed the cosmosGrantStore which helped in fixing this error.
However, the Identity server by default generates reference tokens which are shorter compared to jwt. While use Asp Net Identity Server, jwt tokens were generated, hence the confusion. Later, this useReferenceTokenForApiAuth helped me to use the reference token to authorize Api against the identity server.
Related
We have an SPA that uses MSAL to grab an access token, an id token and a refresh token and caches the tokens in local storage for use later. Behind that we have a Web API running dotnet core 6 and I have configured the authentication in the startup Program.cs like so:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
Then I have an appsettings.json file that contains the AzureAD config section.
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "example.com",
"TenantId": "guid",
"ClientId": "guid",
"Scopes": "access_as_user"
}
This seems to work fine. The [Authorize] attribute protects the controllers by requiring a token. My question is, without a client secret, how can I trust the access token coming from the SPA? Is there some magic going on here in the AddMicrosoftIdentityWebApi method that verifies the token?
I had a quick look in the source but didn't find anything.
Disclaimer: not an expert in the topic, answering based on my own experience using Teams id tokens. This may not apply to your use case where you're getting actual access tokens client-side
Your backend, when configured with Microsoft.Identity.Web, needs to reach out to Microsoft Identity platform (Azure AD) in order to be able to authenticate either the user or the app itself. That's done using a client secret or a client certificate. But the tricky thing here is when does that happen and whether it happens automatically or not.
This is my experience using Teams tokens:
If you disconnect the server from the Internet, AuthenticationMiddleware will make your requests fail immediately,
If you try to call the API with a token generated from another tenant, the request won't get through due to a mismatch in the audiences.
So there's certainly some protection level when not providing that client secret/certificate, but I can't tell you with confidence up to which point.
However:
If you don't provide the client secret and try to make use of, let's say, ITokenAcquisition.GetAuthenticationResultForUserAsync() to authenticate on behalf of the user, you will get an exception like this:
MSAL.NetCore.4.44.0.0.MsalClientException:
ErrorCode: Client_Credentials_Required_In_Confidential_Client_Application
Microsoft.Identity.Client.MsalClientException: One client credential type required either: ClientSecret, Certificate, ClientAssertion or AppTokenProvider must be defined when creating a Confidential Client.Only specify one.See https://aka.ms/msal-net-client-credentials.
Same for authenticating on behalf of the app with ITokenAcquisition.GetAuthenticationResultForAppAsync().
Once again, my use case seems to be slightly different than yours since I only get a useless-by-itself Teams id token client-side, so user authentication server-side is required and that's when the Teams token <--> Actually useful tokens exchanges happen with Microsoft.Identity.Web's help.
I am using AWS Cognito's hosted UI for user login. The id token is returned as part of the URL as described in https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html. Namely,
You can find the JSON web token (JWT) identity token after the #idtoken= parameter in the response. Here's a sample response from an implicit grant request. https://www.example.com/#id_token=123456789tokens123456789&expires_in=3600&token_type=Bearer
However, putting sensitive data in a query string is considered a bad practice (Is an HTTPS query string secure?). Does AWS Cognito support a more secure way of returning the id token?
Instead of token you can ask cognito to send you the Authorization code.
From Documentation:
The authorization code grant is the preferred method for authorizing end users. Instead of directly providing user pool tokens to an end user upon authentication, an authorization code is provided. This code is then sent to a custom application that can exchange it for the desired tokens. Because the tokens are never exposed directly to an end user, they are less likely to become compromised.
Source: https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/
I am using the JWT middleware + ASP.NET Identity to establish a simple User/Password login in my ASP.NET Core WebAPI project.
The tokens will be valid for 15 minutes. I think I will be utilizing the Refresh Token concept to keep the user logged in, when he is still browsing the site (SPA) or using the mobile app (What about a remember me option? I would create a token that's valid for a month maybe?)
So, is there any way to revoke a generated token? I am think about checking (on each request) if the user still has the right to access the API. Maybe there is another way to handle these cases?
I see a AspNetUserTokens table. Maybe there is a way to store the JWT in there automatically?! At the moment I am using ASP.NET Identity just for user authentication.
You can refer to this article : http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
Once the user obtains long lived access token he’ll be able to access the server resources as long as his access token is not expired, there is no standard way to revoke access tokens unless the Authorization Server implements custom logic which forces you to store generated access token in database and do database checks with each request. But with refresh tokens, a system admin can revoke access by simply deleting the refresh token identifier from the database so once the system requests new access token using the deleted refresh token, the Authorization Server will reject this request because the refresh token is no longer available (we’ll come into this with more details).
The simple way is to issue short lived access tokens ,if you want to revoke the user , revoke the refresh token as the article shows , clear refresh token and access token on client side . Of cause , access token is still active until it expires .
Another way is to use Identity Server 4 Reference Tokens :
http://docs.identityserver.io/en/release/topics/reference_tokens.html
IdentityServer will store the contents of the token in a data store and will only issue a unique identifier for this token back to the client. The API receiving this reference must then open a back-channel communication to IdentityServer to validate the token
I am trying to choose between Auth0 and Firebase as my identity provider. I am building a SPA with a Backend API and I would like to use Auth0 or Firebase for all the logic regarding users/passwords/access rights and etc.
Auth0 uses OIDC, which is kinda standard, but IMHO overengineered and very complex. It has separate tokens for identity (ID Token) and for accessing backend resources (access token), whereas firebase uses a single token (if I understand correctly).
So my question here is what authentication mechanism is Firebase using and why a single token is enough in this case?
Firebase Authentication uses two token types:
a long-lived refresh token that identifies the user
a short-lived ID token that validates that the user has access to the backend services
So it sounds like the two are pretty similar.
Let's take an example where we have an SPA accessing an API using the OIDC implicit flow.
Since OAuth scopes are coarse-grained, it is often necessary to perform additional authorization on the resource servers. This can be the case for example when accessing dynamic resources (e.g filesystem) via an endpoint - where access is restricted by permissions tied to the userId, but it is not practical to use OAuth scopes only because of the dynamic nature of the resources.
In these cases the endpoint itself can be protected by an OAuth scope, while access to the resources that the endpoint operates on (e.g files) will be granted based on the userId. Hence the user's identity must be securely sent in the API request.
An obivious choice can be to send the ID token that was obtained when authenticating, together with the access token that was obtained at the same time.
There is a standard way for sending the access token in a HTTP request (the Authorization header), but is there one for the ID token? Or should I just make up a header name like 'X-Identity'?
To answer the question: there is no standard for passing the ID token in an HTTP request.
But arguably there doesn't need to be one: in this case you may not need OpenID Connect since scopes are not the only information that can be associated with an OAuth 2.0 access token as you seem to suggest.
You can "associate" the userId with the access token so that the Resource Server can grant the Client access to the protected resource based on the identity of the user who granted the access token to the Client.
The "association" is implementation dependent: the access token can be a JWT that contains the userId claim or the access token can be an opaque value that the Resource Server can introspect/validate at the Authorization Server to obtain the information associated with it.
Instead of passing it in the header, you can pass it as a query parameter:
curl "https://resourcePath?auth=<ID_TOKEN>
Here's the reference:
https://firebase.google.com/docs/database/rest/auth#authenticate_with_an_access_token