Ok, user authenticates and client gets the JWT from my IS4 instance. All that works. Now, for reasons I still cry at nights after being tormented by people who authoritatively claim to know OAuth but do not, the client is sending me the identity token JWT over the wire to an action, and I need to do some work based on the subject in it. I want to minimize the fallout of this decision and prevent a situation where someone plants me a fake token, so I want to validate the JWT to make sure it came from me, that indeed I am the one who issued it. To simplify, I need to act as both the client and the server in the token validation process, while running on the IS4.
Since this is such a violation of OAuth protocol, I am not sure this is supported out of the box, but here comes: is there a way to do this? I even tried to introspect the token, but that requires an authentication context, and I can't seem to get the client credential flow working since I only use openid/profile scopes and they are not supported by the client credential flow (since the user is defined only in JWT).
The receiver of a token should always validate the signature of the token to make sure it came from your IdentityServer. This is usually automatically done by most proper JWT-libraries. The library will download the public-key from your IdentityServer and use it to verify the signature of the token.
If you are using ASP.NET, then the JwtBearer library will do that for you.
Related
I'm looking for guidance and/or best practices in implementing step-up authentication. The generic scenario is as follows: user logs in to web app using some identity provider, user then goes to some specific area of web site which needs to be protected by additional MFA, for example OTP. All functionality for the website is via REST API, authenticating with JWT bearer token.
The best description of the flow I found is from Auth0 here. Basically, user acquires the access token with scope which is just enough to access APIs that do not require additional protection. When there is a need to access secure API the authorization handler on backend would check if the token has the scope indicating that the user has completed the additional MFA check, otherwise it's just HTTP 401.
Some sources, including the one from Auth0, suggest using amr claim as an indication of passed MFA check. That means that identity provider must be able to return this claim in response to access token request with acr_values parameter.
Now, the detail that is bugging me: should the frontend know in advance the list of API that might require MFA and request the elevated permissions beforehand, or should frontend treat the HTTP 401 response from backend as a signal to request elevated permissions and try again?
Should identity provider generate relatively additional short-lived token to access restricted APIs? Then, if frontend has 2 tokens it must definitely know which token to use with which API endpoint. Or maybe identity provider can re-issue the access token with normal lifespan but elevated permissions? Sounds less secure then the first approach.
Finally, do I understand the whole process right or not? Is there some well documented and time-tested flow at all?
CLIENTS
Clients can be made aware of authentication strength via ID tokens. Note that a client should never read access tokens - ideally they should use an opaque / reference token format. Most commonly the acr claim from the ID token is used.
This can be a little ugly and a better option can sometimes be to ask the API, eg 'can I make a payment'? The client sends an access token and gets a JSON response tailored to what the UI needs. The API's job is to serve the client after all.
APIs
APIs receive JWT access tokens containing scopes and claims. Often this occurs after an API gateway swaps an opaque token for a JWT.
The usual technique is that some logic in the Authorization Server omits high privilege ones, eg a payment scope or claim, unless strong authentication was used.
It is worth mentioning plain old API error responses here. Requests with an insufficient scope typically return 403, though a useful JSON error code in an error object can be useful for giving the client a more precise reason.
STEP UP
As you indicate, this involves the client running a new code flow, with different scope / claims and potentially also with an acr_values parameter. The Curity MFA Approaches article has some notes on this.
It should not be overused. The classic use case is for payments in banking scenarios. If the initial sign in / delegation used a password, the step up request might ask for a second factor, eg a PIN, but should not re-prompt for the password.
CLIENTS AND ACCESS TOKENS
It is awkward for a client to use multiple access tokens. If the original one had scope read then the stepped up one could use scope read write payment and completely replace the original one.
In this case you do not want the high privilege scope to hang around for long. This is yet another reason to use short lived access tokens (~ 15 minutes).
Interestingly also, different scopes the user has consented to can have different times to live, so that refreshed access tokens drop the payment scope.
ADVANCED EXAMPLE
Out of interest, here is an interesting but complicated article on payment workflows in Open Banking. A second OIDC redirect is used to get a payment scope after normal authentication but also to record consent in an audited manner. In a normal app this would be overkill however.
I'm considering a microservice architecture and I'm struggle with authorization and authentication. I found a lot of resources about oauth2 and openid connect that claim they solve the issue but it is not clear enough for me.
Let's consider we have a following architecture:
In my system I want to add a feature only for a certain group of users defined by role. I want to also know the name of the user, their email and id.
After my research I find the following solution to be a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token (being a JWT) that contains name, email, id and role of the user. The response contains a refresh token as well.
SPA application stores the token and attaches it to every request it makes.
Microservice 1 and Microservice 2 check if the token is valid. If so, they check if the role is correct. If so, they take user info and process the request.
How far away from the good solution I am? The login flow looks like Implicit flow with form post described here but with implicit consents and I'm not sure if it's fine.
Moving forward, I find passing user data in JWT (such as name, email) to be not a good solution as it exposes sensitive data. I found resources that say it is recommended to expose only a reference to a user in token (such as ID) and replace such token with a classic access_token in reverser-proxy/api gateway when sending a request to a microservice. Considering such solution I think that following scenario is a good start:
SPA application displays login form.
User fills in the form and sends POST request to authN&authZ server.
The server replies with access token and refresh token. API gateway (in middle) replaces access token with ID token and stores claims from access token within its cache.
SPA application stores the token and attaches it to every request it makes.
Handling a request, API Gateway takes ID Token and based on the user ID generates a new access token. The access token is send to microservice 1 or microservice 2 that validate it as previous.
How do you find such solutions? Is this a secure approach? What should I improve proposed flow?
Thanks in advance!
You are on the right tracks:
ZERO TRUST
This is an emerging trend, where each microservice validates a JWT using a library - see this article. JWT validation is fast and designed to scale.
CONFIDENTIAL TOKENS FOR CLIENTS
Internet clients should not be able to read claims that APIs use. The swapping tokens in a gateway concept is correct, but the usual approach is to issue opaque access tokens here, rather than using ID tokens. At Curity we call this the Phantom Token Approach.
SECURE COOKIES IN THE BROWSER
One area to be careful about is using tokens in the browser. These days SameSite=strict HTTP Only cookies are preferred. This requires a more complex flow though. See the SPA Best Practices for some recommendations on security.
SPAs should use the code flow by the way - aim to avoid the implicit flow, since it can leak tokens in the browser history or web server logs.
SUMMARY
All of the above are general security design patterns to aim for, regardless of your Authorization Server, though of course it is common to get there one step at a time.
Don't use your own login form. As Garry Archer wrote, use the auth code flow with PKCE which is the recomended flow for applications running in a browser.
If you don't want to get an ID token, don't ask for the openid scope in the initial auth request. The type of issued access tokens (JWT or opaque) can often be configured on your OAuth2 server. So I see no need to issue new tokens at your gateway. Having more token issuers opens more ways of attacking your system.
Your backend modules can use the userinfo endpoint, which will give them info about the user and validate the token. This way, if the token was invalidated (e.g. user logged out), the request processing will not proceed. If you validate just a JWT signature, you will not know about the token being invalidated.
If you plan to make requests between your backend modules as part of of a user request processing, you can use the original access token received from your SPA as long as your modules are in a safe environment (e.g. one Kubernates).
Is it really required to validate the access token by decrypting it using the public key? I am asking this question related to the Azure AD. I am understanding that the JWT token can be validated to make sure it was in deed signed by Azure AD. If this is the case, are there any Azure AD endpoints where I can pass the token and get a response whether it was signed by it? All the articles over the internet explains the manual way of grabbing the public key from Azure AD endpoint and then do the decrypt steps by ourselves. Are there any automated way to validate the access tokens?
It would be great if someone can throw light on whether its a standard practice for the APIs to validate the access tokens before servicing the request.
It is considered best security for APIs to validate JWT access tokens on every request. This approach is fast and scales to a microservices architecture, where Service A can forward the access token to Service B and so on.
The result can be termed a 'zero trust architecture', since both calls from internet clients and clients running within the back end involve digital verification before the API logic runs.
You are right that a certain amount of plumbing code is needed to verify JWTs. This is typically coded once in a filter and then you don't need to revisit it. For some examples in various technologies, see the Curity API Guides.
I can confirm that this approach works fine for Azure AD - please post back if you run into any specific problems.
Some Authorization Servers also support token validation via OAuth Introspection, but Azure AD does not support this currently.
Introspection is most commonly used with opaque access tokens (also unsupported by Azure). See the Phantom Token Approach for further details on this pattern.
Yes, you should validate it every time. The reason to use JWT is to authorize request. If you don't care who sent the request and it doesn't matter if it was a hacker or your customer than don't use jwt and oauth. If you do care and use it you have to be sure that the jwt was not changed by some hacker, so signature has to be checked.
I'm writing a web service which uses OAuth2 for authorization. I'm using C# and WCF, though this isn't really pertinent to my question. Having never used OAuth before, I've been doing my research. I'm on the "verify they're actually authorized to use this service" end of things. I think I have a pretty good idea of how OAuth2 works now, but one aspect of it still confounds me.
OAuth2 is token-based. The token is just text and contains some information, including a "secret" that only your application (the web service, in my case) and the Authorization Server knows. The secret can be just a text phrase or a huge string of semi-random characters (sort of like a GUID). This "proves" the user contacted the Authorization Server and got the secret from it. What confuses me is this only seems to prove that the user contacted the Authorization server sometime in the past. In fact, it doesn't even prove that. It just proves that the user knows the secret. The rest of the token (such as role, duration, other stuff) can all be faked. Once the user gets one token for the service he wants access to, they could whip up new tokens with falsified information as much as they like. In fact, there could be numerous servers set up with thousands of "secrets" for nefarious individuals to use at will. Of course, this wouldn't happen often, but it seems very possible.
Am I correct, or is there something I'm missing? Is this a known weakness of OAuth2?
Whenever the Resource Server (or "service") receives a token, it needs to validate it. Depending on the token type it can check its signature that was created with the private key that Authorization Server has or it can call into the Authorization Server to validate the token. This way a user cannot forge a token: it would be impossible to forge the signature or to make the Authorization Server verify a token that it did not issue.
FWIW: you seem to be conflating the "token" and "client secret" and perhaps even the private key of the Authorization Server; they're all different concepts.
So I've got OpenID+OAuth hybrid working with DotNetOpenAuth when connecting to google. It gives me back a Authorized token so I need to exchange it for an access token.
I seem to be coming in about midway through a normal OAuth workflow in DotNetOpenAuth. I also seem to be missing somethings that DotNetOpenAuth wants like the the token secret and verifier. However according to the graph here I shouldn't need them.
Any ideas how to easily swap the auth token for an access token with DotNetOpenAuth?
Since you're talking about the OpenID+OAuth hybrid I expect you're writing a web app (as opposed to an installed app). DotNetOpenAuth should only be asking you for a verifier code if you're using the DesktopConsumer class, which is inappropriate for you. Use the WebConsumer class instead and the verifier will be taken care of for you. Swapping the request token for an access token will be automatic as you call the simple methods on WebConsumer, I hope.
As for the token secret, all token secrets are managed by your implementation of ITokenManager, which will save and retrieve token secrets on demand within your database.