Want NGINX to authenticate incoming requests based on an OAuth2 token INCLUDING validating specific token claims e.g. "aud" audience claim, "iss" issuer claim etc.
ngx_http_auth_jwt_module (http://nginx.org/en/docs/http/ngx_http_auth_jwt_module.html) only validates the token to ensure it's signed by an expected party and validity period.
Issue is if you're using an cloud IdP (e.g. Azure AD) the above validations are insufficient as keys used to sign tokens are shared across different customer tenancies. Therefore claims in the token need to be additionally validated including the issuer, audience etc.
How can this be done with NGINX? The following module supports claims validation however is now archived:
https://github.com/auth0/nginx-jwt
ngx_http_auth_jwt_module exposes variables that contain claims decoded from the JWT payload, including aud and iss, which will appear in variables $jwt_claim_aud and $jwt_claim_iss correspondingly. You can read more in the documentation under Embedded Variables section.
Having these variables, you can use them in combination with auth_jwt_require directive to validate the claims during access stage:
auth_jwt_require
Defines additional conditions for JWT validation. The value can contain
text, variables, and their combination. The authentication will succeed
only if all the values are not empty and are not equal to “0”.
map $jwt_claim_iss $valid_jwt_iss {
"good" 1;
}
...
auth_jwt_require $valid_jwt_iss;
One more thing, while ngx_http_auth_jwt_module is a part of commercial distribution (and you should definitely leverage it if you have Nginx Plus already), there are also quite a few free JWT modules for Nginx written by the community. Some of them also support variables and claims validation.
Related
I have a backlist of tokens (JWT) stored in Redis and would like to enable users of my website to blacklist their tokens in a RESTful way.
I can either:
Build the route /sessions/<token> with a DELETE method
Build the route /sessions/ with a DELETE method and the token sent in the request body.
The first solution is simple but the token is stored in the server's logs and in the user's browser's history.
The second solution seems better but I'm not sure I'm not breaking HTTP RFC's idempotency principle by sending a DELETE request with a body.
What's the best practice in this case?
Is JWT in URI a bad practice?
JWT tokens are URL-safe when it comes to the syntax. From the RFC 7519:
A JWT is represented as a sequence of URL-safe parts separated by period (.) characters. Each part contains a base64url-encoded value. [...]
However, when using JWT as bearer tokens, it's advisable to avoid sending them in the URL. See the following quote from the RFC 6750:
Don't pass bearer tokens in page URLs: Bearer tokens SHOULD NOT be
passed in page URLs (for example, as query string parameters).
Instead, bearer tokens SHOULD be passed in HTTP message headers or
message bodies for which confidentiality measures are taken.
Browsers, web servers, and other software may not adequately secure
URLs in the browser history, web server logs, and other data
structures. If bearer tokens are passed in page URLs, attackers might
be able to steal them from the history data, logs, or other unsecured
locations.
For the situation mentioned in your question, you may not need to send the full token. You could give the token a unique identifier (stored in the jti claim) and then send only the token identifier to the server.
See how the jti claim is defined in the above mentioned RFC:
4.1.7. "jti" (JWT ID) Claim
The jti (JWT ID) claim provides a unique identifier for the JWT.
The identifier value MUST be assigned in a manner that ensures that
there is a negligible probability that the same value will be
accidentally assigned to a different data object; if the application
uses multiple issuers, collisions MUST be prevented among values
produced by different issuers as well. The jti claim can be used
to prevent the JWT from being replayed. The jti value is a case-
sensitive string. Use of this claim is OPTIONAL.
A UUID should be unique enough to identify your tokens without collisions.
You don't need to store the full token in the blacklist either: store only the value of the jti claim and some other claims that you may find relevant (such as sub and exp, for example).
DELETE requests shouldn't contain a body. So you could use DELETE /sessions/{id}, where {id} is the unique identifier of your token.
I've used Firebase Auth to manage user logins on my app, and custom claims for their roles and permissions for each organization they belong to.
The problem is that when a user belongs to several organizations, the custom claims exceed the 1,000 characters length limit set by Firebase Authentication.
For the client, I can make an API call with the ID token, and respond with his/her claims. But for my gateway, it means I now need to query my database at each user request. It defeats the point of JWT at all.
How can I embed custom claims in a safe way?
Desktop Client: ReactJS + Firebase SDK
API Gateway: Express on NodeJS
Backend: Firestore for user metadata
Usually the keys and values of custom claims are very short, and you should not run into this limit. Short keys and values are important, since the claims are encoded in the JWT, which is sent with each request/connection.
You are likely storing readable, meaningful values in your token now. I'd recommend using shorter "codes" as the keys/values of your claims, similar to the three letter default properties of a JWT. That will keep your token size under control, and should bring you back under the limit unless really have a lot of claims.
There's an open feature request for Metabase to support IAP. I took a stab at it, and have a Clojure implementation of the steps detailed in Securing your app with signed headers (i.e. verify token header, verify token payload, retrieve user identity).
But this question isn't necessarily specific to Metabase. The general idea is to replace Google Sign-In and only use only IAP signed headers for authentication and user creation in an application on Google App Engine (specifically, GAE flex environment).
The "problem" is that the user identity information from the IAP token looks like: {"email":"alice#example.com","sub":"accounts.google.com:118133858486581853996"}. I also came across Using special URLs, but this returns something like: {"email":"accounts.google.com:USER_EMAIL","sub":"accounts.google.com:118133858486581853996"}.
With a Google Sign-In token, I can obtain values for given_name and family_name along with email, which means I can fetch-or-create a valid Metabase user. Is there a way to get the first and last name via the JWT sub, (i.e. accounts.google.com:118133858486581853996)?
Hm, if they have a public profile you can pass the number after "accounts.google.com:" to https://developers.google.com/+/web/api/rest/latest/people/get . Unfortunately, you won't be able to authenticate to that API as the user, since IAP doesn't currently provide a way to call let users delegate access to call Google APIs. (You'll have to use a service account to call that API.)
The other solution would be, if IAP provided a way to a) specify additional scopes in its OAuth request to Google, and if it then b) passed additional claims from the OIDC token into the IAP JWT, you'd be able to configure IAP to request the "profile" scope. However, IAP currently only requests the "email" and "openid" scopes, and doesn't have a mechanism for specifying additional scopes.
-- Matthew, Google Cloud IAP engineering
I am trying to implement JWT authorization based on this article.
I also need to let specific users (admins) impersonate other users (clients).
I see two possibilities here:
make admin requests using the admin token and add the impersonated client_id to each of the request;
request a new token for the admin which will contain the username and roles of the CLIENT in its payload, so it will basically become a client token, but it will also have two extra fields: "impersonated=true" and "impersonator_admin_id=x".
I would prefer the second one as it would be easier to use the .net built-in authorization attribute with the clients roles.
But I'm not sure if this opens up security holes or if it can be actually implemented using .Net's OAuthAuthorizationServer.
From your links, first decide if the admin is impersonating an user or acting on behalf of. Note that on-behalf-of != impersonation
A acts on behalf of B when A maintain its own identity and is given all rights from B
A impersonates B when for all intents and purposes A is B
In JWT RFC is not defined any specific claim for this purpose. In this draft the author proposes to include an on-behalf-of claim obo
{"obo": {
"prn":"mailto:joe#example.com",
"ctx":["urn:adatum.com:calendar"]
}}
prn identifies the principal for whom the bearer of the JWT is acting on behalf of.
ctx stablish permission contexts in which the bearer is allowed to act on behalf of the principal. This claim should by mandatory to restrict the contexts in which the delegated rights are to be exercised
Note that the obo claims are not included in IANA's JSON Web Token Claims, so they should be taken as a recommendation. There is a similar claim azp in OpenID but it is not clear how to apply it
azp : Authorized party - the party to which the ID Token was issued
Answering your question, in the first case I think you are talking about acting on-behalf-of, so include the client_id and the security context. The second case would be impersonation.
Impersonation always comes with serious security implications as it allows "to become someone else".
For that reason, you would need to make sure to make this state as visible as possible by e.g. introducing intensive audit logging. Also (to distinguish between real logins and impersonation logins) you would want to be able to transfer information about this very special state within your JWT access tokens by e.g. adding additional impersonated and impersonator properties to the profile of the impersonated user (as you described in your second point).
In the end you would probably end up having an regular API endpoint excepting requests like this ...
POST https://YOUR_DOMAIN/users/{user_id}/impersonate
Content-Type: 'application/json'
Authorization: 'Bearer {ACCESS_TOKEN}'
{
impersonator_id: "IMPERSONATOR_ID"
}
... which would hand out specific impersonation tokens that would allow to use service "through the users eyes".
I'm writing a SOAP service with a basic authentication. To decide, whether the consumer may access a resource, I analyze his credentials. But I also need some additional information: The firm the user (as person) belongs to.
A user can belong to multiple firms. So he can e.g. access documents like my_document_xyz_a when logging in as an employee of the firm firm_A and documents like my_document_xyz_b when logging in as an employee of the firm firm_B.
So I / my SOAP server need/-s the credentials (username and password) and the firm name (or token).
Which HTTP header is appropriate for this purpose? Or should I use a custom header HTTP header?
Just simply add a security section in your SOAP method schema to pass the user role.
But if you really want it in the header (because your code is already parsing HTTP headers to obtain the authentication info) then use a cookie.