Best practice: Wrapping 3rd party IdP access-token - security

Our situation:
We are currently implementing a sensitive flow in which the resource owner gives us access to retrieve their data as a one-time operation through a trusted 3rd party identity-provider.
Authentication happens through OIDC with the OAuth Authorization-code flow and PKCE.
What we want to achieve:
After a succesful client authentication at the IdP and we are provided with an access-token to retrieve the resource owners data; instead of exposing the IdP access-token directly to our front-end client, we would like to wrap the original IdP access-token to restrict resource access through our back-end client.
The question(s):
Is it considered bad practice to extend/wrap an existing access-token?
My idea is that we wrap the token by encrypting it using symmetric encryption (AES-256 CBC using a secured key and random salt at each encryption), so that only our back-end can decrypt the original access-token and fetch the resource owner-data. That way we can pass the wrapped token to our front-end, and restrict their resource retrieval access through our back-end. However I am uncertain if there is a better way of achieving this.
Note:
I have also considered if we should generate and store an entirely new reference access-token, but I would like to prevent that, as it transfers part of the security responsibilities to our service rather than the IdP. We want to rely on the expiration and security of the original IdP access-token.

Related

How safe is an acess token?

I have been reading about OAuth 2.0 Authorization Code flow to protect APIs in microservices architectures but I dont understand how an access token issued by the Auth Server is supposed to protect an API hosted in another server.
Is that same access token also kept in the API and when the client tries to access it with the access token issued by the Auth Server, the API checks if contains it? If so, does that mean that the access token is sent both to client and the protected API in the authentication process?
I hope to have explained my problem well. Thanks in advance.
Anunay gave a pretty good analogy of how JWTs work at a high level as portable, trustable identifier, but since OAuth supports more than just JWT authentication it might warrant sharing a bit more detail.
Token introspection
In your question you rightly assumed that tokens need some way of being trusted, and that one such way would be to store the token in a private database and do a lookup whenever a token is presented to determine its validity. You would absolutely be able to instrument a valid OAuth server using a method like this by issuing the token using whatever form you wish and writing an introspection endpoint that performs the lookup. The OAuth spec is intentionally abstract so that the functional behavior of token introspection can take many forms.
One of the reasons for this level of abstraction is because while storing the tokens for direct lookup might be easy, it means that you have to store copies of these tokens in some form in a private database for comparison. This storage would in turn make you a honeypot for bad actors, both internally and externally, who would seek to impersonate your users en-masse. It's for this reason that many implementations of OAuth prefer to issue and validate tokens using public/private key encryption instead of direct lookups. This process is very much like the one Anunay described in his comment in that it issues tokens that are signed with a private key and verified with a public one. With this process, you no longer need to keep everyone's token in a private database, and instead simply need to secure private and public keys that are used to sign and verify tokens respectively.
JSON Web Tokens (JWTs) and reducing number of introspection calls
Anunay's response specifically referred to a common token structure that is generated using public/private key encryption and issued to users, JSON Web Tokens. These tokens are structured in such a way that they include the user information a backend service might need like the User ID, email address, and sometimes more, in a raw format that is directly readable to the backend API. In addition to this raw information however, JWTs include a duplicate copy of the data, but this duplicate copy is private-key encrypted. In order to trust a JWT token, all you have to do is use the public key and ensure that the private-key encoded payload is verifiable by applying the public key to the raw payload. Since public keys rarely change, many backend services cache the keys used for verification and elect not to do a token introspection on the issuing server since they already can verify the payload. This is how you'd optimize throughput on backend services that are protected via OAuth.
Since public keys can only be used to verify payloads and not produce them, these public keys are often broadcast by the servers that issued the tokens allowing anyone to "trust" the tokens it issues if they so choose. To learn more about this process, I'd recommend you research OpenID Connect.
Access token can be understood as an passport that government issue to the citizen based on proof of identity.
When you take it to another country, they look at the document and trust it because they trust the country and you because you are the holder of that document with you details.
They trust the fact that passport cannot be fiddled with and allow you entry
Now for access token, in very simple terms, authorization server verifies the user. Once verified it issues the user a JWT token (Access Token). This token is signed with private key. It has your details and is encoded along with signature. Now you can take this token to any third party who has got the public key and trust the authorization server. Now when you share the access token with this third party, it use public key to verify the token and check for expiry. If valid it allows you in.
So API doesn't really need to talk to auth server or keep any details about the token. All its needs is a public key to decode the token.
Now there are two important things. One if you ever let loose your access token, or some one who is not intended to get hold of your token gets it, he can do what ever he wants and auth server will not be able to do much. However as you see this approach reduces the chattiness of the systems specially microservices.
So to address this we limit the expiry of access token. Like passport, it comes with expiry. Shorter you keep it,user have to go and get the token refreshed with auth server. Every time he does so, auth server gets a change to verify creds and other details. If they do not match access token will not be refreshed.

Why use an idp issued id_token -- versus a custom session cookie?

I'm struggling to understand when to use a session cookie, or just use the IdP issued token as a bearer token.
Is the primary advantage of using an IdP issued token that you get a standards based mechanism for tokens (including ensuring non-tampering, as the JWT is signed)?
As opposed to using a proprietary vendor mechanism of converting it to a claim identity, and then to a custom session cookie (as per owin middleware)?
Doesn't the custom cookie approach have an advantage that one can add non-ipd issued claims (eg: from a system db)?
What other key advantage does using an idp issued id_token have over a cookie based session approach?
Is it maybe that a bearer token approach would not need caching on the server, so that one can re-use it to call 3rd party services that have a different audience value? Whereas the token would be lost if we used a cookie? (I'm reaching, I know, as I don't yet understand how calling 3rd party services works).
The Id token is meant for your user-facing app as proof of who the user is.
It is then up to your app how you choose to authenticate the user on future requests.
While technically you could just store the Id token and use that, as you mentioned, it cannot be extended since it is digitally signed.
Which for most our projects is no good.
At least in regular Azure AD (not sure about B2C), you cannot use the Id token to get an access token for another API.
In there, you would have to get an authorization code in addition to the Id token at the time of sign in,
and exchange that for an access token (which you then cache server-side).
If you use the Id token as an authentication token for your app, keep in mind that Id tokens issued from the token endpoint (when exchanging an authorization code in normal Azure AD) are not signed (I guess since you receive them as a response to your request + over HTTPS).
Only the Id token you get in the redirect back to your app is signed in normal AAD.
I am not sure if this applies to B2C as well.

LDAP JWT OAuth scheme explanation

I'm trying to systematize my knowledge about oauth + jwt + LDAP authorization. I've read multiple excellent articles (i.e. this) but still have a questions about about that:
My understanding:
JWT is a token which allow Single Sign-On (SSO). It's more secure than simple token auth since it encrypts all user specific info (e.g. userName, password, clientAppId, ip address etc.). This info is signed with internal authority server key and can't be changed by attacker.
From here, look at phrase below. As I understand that means that each of HTTP frontend servers doesn't require lookup for session data. But it requires lookup to authority server. What's the benefit? Isn't that the same single point of failure? Why JWT is considered STATEless? JWT still needs to keep user data on authority server, right?
The server side storage issues are gone.
If you need log out user with JWT before expiration period gone - you need to keep black lists. So what the benefit over simple token uath without SSO?
Is JWT a realization of OpenID (authentication only)?
It's impossible to do auto-sign-in for server-2-server with JWT (tokens) without OAuth. Oauth is used when you nwant ot authorize request from some service on behalf of user without user participation. Why it's impossible with tokens and possible with OAuth?
OAuth is also used to configure flexible access policies, like roles, groups etc. But why you can't implement them yourself based on tokens/JWT?
LDAP server is extremely fast for read operation on small not-interconnected pieces of data ,as user credentials. Where is LDAP in jwt-oauth scheme (or in OppenID Connect)? Is LDAP used for authentication (JWT)or authorization (OAuth)?
I'll try to clarify some concepts here:
Oauth and OpenID Connect (OIDC) are just authentication mechanisms by themselves. JWT is just a way to convey authenticated information between two parties. So, you have to do an effort of separation of concerns. When having doubts about how to identify an user, and be sure it's really him/her, check credentials and so... go check OIDC or Oauth standards. Whn in doubt about how to convey user related information between parties securely then, look at the JWT RFC and related (JWS, JWK, JWE and related).
Having said this:
Totally correct. You understood correctly.
It depends on implementation, but some stateful approaches exists, and also some implementations are stateless. The JWT-consuming server (Resource server in Oauth jargon), can possibly have the IdMS's (Authorization server (badly-named) in Oauth jargon) signing keys in cache, or pre-provisioned. This way, it can validate JWT Access Tokens coming from the IdMS without having to do any request. The IdMS could be down without impacting the system. This is precisely the case for some architectures that have the IdMS behind some VPN, and the Resource Servers outside it. Besides that, there could be a more stateful way of checking Access Tokens against the introspection endpoint of the IdMS. With this way, for each validation required on the Resource Server, a request would be made to the IdMS to check the Access Token is still valid and to extract the related claims. This latter mechanism is used also when the Access Tokens are not JWT and thus opaque.
Blacklists could be a way to do it, but it is more usually done through Refresh Token mechanism. You give the Access Token a very short lifetime, like 1 minute, and then rely on the refreshing mechanism to fail in case the session is revoked.
Technically speaking OpenID and OpenID Connect (OIDC) are different beasts. For shortness sake, we could say that OpenID is an old implementation of identity federation that did not see great adoption. OpenID Connect is an evolution of Oauth 2.0 that adds JWT, ID Token and some other niceties. But no, JWT and OIDC are by no means an exclusive implementation. It is true that OIDC implies forcefully the use of JWT, but JWT exists outside OIDC.
If you want to authorize requests between two servers, at the basic level, it can be done with simple tokens (Just maintain them secret, and use TLS). But with JWT what is enabled is that the servers can trust a central IdMS without having to trust entirely on each other. Oauth is used in this case you indicate because Google for example, trust himself and the user, but not your server. So, authentication occurs between Google, acting as the IdMS and the user, and this, generates a JWT (Not always, so you see the case for my previous statement) that your server (trusting an external IdMS) can use to communicate with Google.
As already said, groups/role management is independent of JWT/tokens used. JWT/plain tokens are only the way of conveying authentication information.
LDAP on Oauth/OIDC lies in the Authentication phase. When the user sends it's credentials to the IdMS instead of checking against a local database, the credentials are checked against LDAP. LDAP could also be used by some advanced IdMS's to retrieve policies, groups or other permissions. But when the authorization is done, the rest of the process is the same as always.
References:
https://openid.net/connect/
https://es.wikipedia.org/wiki/OpenID
https://www.rfc-editor.org/rfc/rfc7519#section-1

Avoiding replay attacks on Resource Owner flow by using nonce

I'm currently implementing an OpenID Connect authentication system for some apps I'm building, and one of the clients is a native mobile app. Having read about the different options for using OpenID Connect with a native client, it's clear that the current industry recommendation is to use the Hybrid Flow (i.e. show an embedded browser to collect the user's credentials, and then issue a token for the app to use). The alternative is to use the Resource Owner Flow, which has a better user experience in that the credentials are collected inside the app itself. But this seems to be discouraged for two main reasons:
It means that the native client will collect the credentials - so the native client has the opportunity to save the credentials or do something nefarious with them. In our case, we are creating the native client ourselves so this is not a concern. We will not be opening up the authentication system to other applications to use.
Because the Resource Owner Flow is from the OAuth 2 spec, rather than OpenID Connect, it lacks the replay attack prevention features of the other flows. Specifically, someone could record the authentication process, and then replay it themselves in order to obtain a user token from our identity server.
Since issue 1 is not a concern in our case, what I'd like to understand is whether there is a way to add replay attack prevention to the Resource Owner flow by using a nonce/temporary token of some kind. The scenario I'm thinking of is: the app would request a nonce from the identity server, which would include some sort of timestamp or other unique identifier for that request; the app would then need to provide that nonce with the authentication request; the identity server would validate the nonce before it allows the authentication request to be processed. That way, if someone was able to replay the entire message, the server would discover that the nonce is invalid and would reject the authentication request.
It's possible that an attacker could go and request a nonce from the server themselves, but then they would have needed to decrypt the (HTTPS) authentication request to be able to replace the original message's nonce with the new nonce they generated.
My questions are:
Are there any other reasons why the Resource Owner Flow is not a good idea in this situation?
If we did use the Resource Owner Flow, would a nonce approach like I described be a good way of avoiding replay attacks?

Using JWT with Active Directory authentication in NodeJS backend

I am building an intranet web application consisting of an Angular frontend and a Node.JS backend. The application needs to use the corporate Active Directory for authentication and authorization.
I'm considering how to best implement this in a secure way. I am planning to use the Active Directory node module for actually communicating with the AD to authenticate when the user logs in, and to check security group membership for certain restricted actions, etc.
However, I am not quite sure what is the best way to authorize my backend endpoints. The AD module does not offer any token/ticket, even though I suppose Kerberos is used for the actual authentication process. In other authenticated apps I've developed I've generated a jsonwebtoken when the user logs in, and then passed and verified that token in each backend route, is that a good idea also when authenticating against AD?
EDIT: Second part of question spawned to separate thread: Best practices for server-side handling of JWT tokens
Also, I have a more general concern, regarding what the best practice is for actually verifying tokens. Suppose that the "secret" used for JWT generation is compromised (in my scenario many people may have access to the source code of the system, but not to the system itself). Am I right in believing that a malicious user could then, with only this information, generate a token on behalf of any given user, and without ever authenticating with AD use that token in my API requests? A token is typically generated using jwt.sign(payload, secretOrPrivateKey, options).
Alternatively, suppose a malicious user could get hold of an actual token (before it has expired). To me it seems like instead of having to know a user's username and password, the security is now reduced to having to know the username and the JWT secret. Is this a valid concern and what should I do to prevent this?
My best hope so far is using a server side session to store information about the current user after logging in, so that even if a token is maliciously generated and used when accessing backend endpoints, it would fail unless the user has actually gone through the login route, authenticated with AD and stored some information in the session as a result of this.
I also considered actually authenticating with AD in each API endpoint, but that would require the AD username/password to be sent in every request, which in turn would require that sensitive information would have to be stored in the client's sessionstorage or localstorage, which is most likely a bad idea.
So, questions:
1) Is it reasonable to combine AD authorization with JWT as bearer token or what is the preferred way to build a secure backend + frontend utilizing AD for authentication?
2) If JWT is a good idea, what is the best practice for securing endpoints using JWT? Is using a server side session reasonable?
Interestingly enough I have found tons of examples on how to best implement token based authentication (in general, or with NodeJS specifically), but many of them seem flawed in one way or another.
1) Is it reasonable to combine AD authorization with JWT as bearer
token or what is the preferred way to build a secure backend +
frontend utilizing AD for authentication?
It is reasonable, but if you are already using Kerberos and AD to initially authenticate the user, you might consider using s4u2proxy constrained delegation which allows the service to present the user's service ticket to the KDC and acquire (subject to authorisation checks) a ticket for a backend service (and repeat for as many services are necessary).
If you have a lot of backend services that need to be contacted, a single JWT bearing all the authorization claims needed for all the services to enforce authorization policy may be a better option.
2) If JWT is a good idea, what is the best practice for securing
endpoints using JWT? Is using a server side session reasonable?
General key security practices apply:
Never store keys in the clear in non-volatile storage, anywhere.
Ideally do not store encrypted keys in attached storage on the server where, if the server is compromised, they would be subject to offline attack. Make them available to the host only at server startup.
Ensure key material resides in secure memory so that it cannot be swapped to disk (and/or use encrypted swap).
Use public key algorithms so that no secret key need exist on multiple hosts.
Consider using a hardware security module (HSM).

Resources