Is there a thing like asymmetric authorization in web? - authorization

I have a private API, that I want 3rd party clients to authorize without sending sensitive information to the client, like a password. The usual flow in this case is:
We give a secret one time token to a client
Upon activating this token (e.g. calling api with this token)he's able to create an account by providing a password.
Client authorizes with this password and receives a secret token
This secret token is used with every api call.
The issue with this flow is when we're sending him one time token. If someone uses it first, he receives all the data he wanted.
Atm asymmetric encryption is used everywhere, https (ssl) is based on it. I wonder if there's such thing as asymmetric authentification. As I see this flow is:
A client and a server generates 2 magic tokens client_private_token, client_secret_token, server_public_token, server_secret_token.
We save opponents public tokens for example in settings files on both sides.
The server responds with server_public_token
The client uses client_private_token to generate some session_token and send it with every request that requires authorization
The server uses its server_private_token and user_public_token to verify that this session_token is valid.
The flow is very similar to ssl, but instead of encrypting data we just generate magic strings that proof that it's we.
Please don't confuse it with JWT, as JWT is just a payload with some information and server signature with it. To create a JWT user needs to be authorized in the first.
Also if there are such things it would be great to have clients to modern languages like java, js, python etc

Related

Is it ok to send the Client Secret as nonce?

I am building an SPA that connects to my Backend API and I have to integrate Azure AD Login, I am slightly confused about the entire authorization flow. I am trying to be as secure as possible. I will explain the flow below:
I build the url in the backend (containing the tenant id and other info), which is returned to the SPA to be added on a button.
The user clicks the button, is redirected to the Microsoft/Company authentication page.
If the authentication is successful, the user is redirected back to the SPA together with the ID Token.
The SPA takes the ID Token and sends it as a Bearer Token on each request to the API.
The API checks the signature and then validates some of the JWT tokens claims (such as the aud, iss, exp etc).
I have read about the state and nonce parameters, which are sent initially to Azure as a way to increase security, but I am confused between the role of the two.
I want to set the nonce as the client secret, and then verify the claim when it comes back inside the ID Token (step 5).
Is the right way to do it? From what I've read you other use the JWT signature verification & validation OR the Client ID / Client Secret technique, but why can't I use both as in my example when the nonce is the secret.
Secondly, if I use the nonce for this, what should I used the state parameter for? Should I build the state as a random string created by the SPA (so the frontend).
UPDATE: Upon further reading, I realized that you CANNOT use the Client Secret as the nonce, because the entire idea of the nonce is to be unique each and every time. A nonce is in fact a word created and used just one time, after which it is discarded. Seeing as the Client Secret is always the same, it wouldn't mitigate "replay attacks".
I'll keep this post as I still have the following questions:
Is nonce used for the API/Backend to check and state is used by the Client/Browser (e.g. frontend)?
What should I do with the Client Secret? It seems to be useless now. Should I add it as an encrypted custom claim?
FINAL UPDATE:
Besides the accepted answer, please read about Implicit Flow, Auth Code Flow, ID Tokens and Access tokens and the difference between them to understand.
1. Don't implement the protocol, use a library
The best (and easiest) way to implement this securely is to not implement it yourself. Instead, use a trustworthy and well-maintained client library which implements the protocol, leaving you free to focus on the value your app is bringing, rather than on the details of the protocol.
In your case, I would recommend using the Microsoft Authentication Library for JavaScript (MSAL.js). The quickstart for MSAL.js is a good place to start.
2. For SPAs, use the Authorization Code Flow with PKCE
You're trying to implement the Implicit Grant flow from a JavaScript application. Instead, you should switch to using the Authorization Code flow (with PKCE). To do this correctly, you will need to deal with a "code verifier" and a "code challenge" and do some hashing. Instead, you should just use a library (see #1, above).
The latest version of MSAL.js implements the Authorization Code Grant flow with PKCE, and you don't have to deal with this at all.
3. No, do not use the client secret as the nonce.
(Edit was just added, so I won't go into the details of why not.)
Is nonce used for the API/Backend to check and state is used by the Client/Browser (e.g. frontend)?
No, both are used by the client (in your case, the JavaScript app). (In many/most cases, the single-page JavaScript app doesn't send the ID token to its backend, it sends the access token (which will not contain the nonce), so the backend never sees the state or the nonce.)
What should I do with the Client Secret? It seems to be useless now. Should I add it as an encrypted custom claim?
No, don't do that.
For starters, no part of your JavaScript app should have any long-term secret in it (such as the client secret). Remember that anybody who can load the app can look at the code for your app, and see all the traffic between your app and any backend server it calls. If this communication includes a secret, then any user of your app can see that secret.
If you have no use for your client secret, then you just don't need a client secret. For a public client application (which is what you seem to be building), it is normal that you don't need a client secret.

How API gateway validates access token via introspection

I found one interesting article that has this illustration:
It says that:
API Gateway verifies access token for all incoming requests via introspection
But what does this mean?
it says that gateway goes to authorization server and validates token (JWT).
why is that needed?
if gateway has authorization server's public key, it can check token validity using signature just like every backend service, why is introspection needed and how is it done?
Depending on your Identity provider it can be done either way but there are trade offs.
If you validate the token locally then yes it can use public keys to do that and that's very efficient way, however downside is that if the token or signing keys are revoked then your token is still valid. With Remote check you have to bear the http overhead but that is more reliable.
Normally tokens are kept short lived and validated locally. But if your access token are long lived, your application require strict access controls or library doesn't support local validation then it's a good idea to check them remotely
I believe you are looking at this document.
What I understood from this Secure API Gateway is that the gateway is responsible for introspection and the back-end services will only check the token signature, which is less secure than introspection, but still a layer of security.
Introspection is necessary to validate the token information against the Authorization Server.
This is more secure, because the system can ensure that the token received is not malicious, expired and it is from an known source.
The details on how it is done are explained in RFC 7662.
Yes, the gateway could validate the token signature if it has access to the certificate.
I can't really tell why they choose the back-end server to do it, probably a project decision.
API Gateway primarily meant for routing the incoming calls to the corresponding MicroService Clusters.
In addition to that,it can also play a role to validate the token, so that only valid traffic is routed to the downstream servers (filtering malicious traffic).
The level of validation could be up to the product owner/architect decision. It could be as simple as validating against the list of in memory cached token or in depth validation on set of claims, digital signature verification, expiry time, audience claim etc.
You can view the set of claims inside the token using JWT decoder like https://devtoolzone.com/decoder/jwt

OAuth2 2-legged client credentials flow and "confidential" clients -- how to hide the client_secret

I have a REST api that accepts what are essentially anonymous survey responses, i.e., from non-authenticated users. My organization wants to allow a few (maybe 12) partners to develop client apps to collect the responses and send them to the api. I want the api to authenticate these clients, i.e., validate that the client is one of the 12 that we've authorized. I was planning to use the OAuth 2 "client credentials" flow, providing each of these clients with a unique client_id and client_secret. The client would request a token using their client_id and client_secret, and then use that token in subsequent api calls. The clients would be required to be https server-based apps that can keep the client_secret hidden -- i.e., "confidential clients" for the purposes of the OAuth2 spec (https://www.rfc-editor.org/rfc/rfc6749#page-14).
But can the client_secret really be confidential in the client credentials flow? As I understand it, the recommended way to pass the client_id and client_secret is as a base64-encoded value in the HTTP Basic auth header. If an attacker browses to that client app to submit a suryvey response, can't he just use the browser dev tool to see the base64-encoded client_id:client_secret value, decode it, and build his own app using that same client_id and client_secret?
I know I can use CORS to restrict browser-based requests to those from the 12 authorized domains. So I guess I'm really asking about non-browser attacks that try to impersonate one of the authorized clients.
So my questions:
Am I right that this visible base-64 encoded version of the client_id:client_secret presents a vulnerability in a vanilla OAUth2 2-legged client credentials flow (i.e., no end-user to authorize the client)?
Instead of client credentials, I'm thinking we could use a signed-token approach (probably JWT), similar to what's described here, where:
the client server and api server have a shared private key.
the client generates a token, signing it with a hash of the private key plus a timestamp. The client sends that token in the api request, along with the "request timestamp" used for the hash.
the api server validates the token, using the private key and the "request timestamp" to verify the hash. The server accepts only recent timestamps (e.g., within the last 2 seconds) to prevent replay attacks.
Does that sound like a reasonable approach?
Can anyone think of another way to restrict the api to only authorized clients?

Secure Web Authentication and API access

I want to design a web application which guarantees secure authentication and gives API access only to the authorised users. The basic idea is simply sending username and password to get the user authenticated. And user can make request to server with the session_id without authenticating himself again.
Definitely, it is very insecure. But as far as I could understand now, in order not to expose the user's credentials, we can apply TLS(https) to get it encrypted.
However, as I research around, I get acquainted with a lot of concepts, like Base64, HMAC_SHA1, API keys, OAuth1.0. But I could not understand why do we need those mechanism other than TLS. Can anyone help explain why TSL is not enough to ensure authentication and API access to be secure?
Secure sessions work fine if your web application authenticates the user, issues the session id and validates the id on each call. You can store the session id in a secure cookie that gets sent back on each request.
Things get more complicated when you have your API on a different domain. Now your cookies are not automatically sent to the service (same-origin policy). You could of course stick the session id in an Authorization header when you call your API. But now your API needs to talk to the same backend store maintaining your session state to verify the authorization. This backend store becomes a bottleneck in scalability and a single point of failure.
To get around this, modern protocols (like OAuth2) issue security tokens. These tokens are digitally signed (using HMAC) and the receiver trusts the token if the signature is validated successfully. No backend calls are needed to validate the token, just a simple cryptographic operation.
API keys are used to allow applications to get a security token without relying on a user to authenticate. Think of them as a password for an application.
Using security tokens also allows you to use a 3rd party authorization server (like Facebook or Google etc) and completely get out of the business of authenticating users, storing passwords, issuing tokens etc.

How to maintain user session in the client?

So I have a REST API. I followed this tutorial in setting up client authentication. I'm done with that. Now the next part is user authentication. What I have in mind is like this:
The client sends the login details to the API.
The API validates the username and password and generates a token that is sent back to the client.
The client stores the token somewhere and use it for authentication for subsequent requests.
The questions, is this a proper way of maintaining sessions in setups like this? Are there better ways in implementing this? I'm very new to this type of thing so please be elaborate with your answers. Please note that the API is pure REST and client could be anything(eg. Angular, iOS, Android app). So it's not typical in the sense that the front-end is not on the same server as the API.
You could do that but you would be going off the beaten track of proven security patterns. This probably isn't wise and will give you lots of extra work and headaches. However, here's one service provider that exposes a REST API and created their own extension of OAuth. It is similar to what you outlined so I list the steps here to serve as an example but not necessarily recommending you follow:
Consumer Application collects the User's credentials directly
Consumer Application concatenates the user name and password with a space and base64 encodes the credentials
Consumer Application puts the encoded credentials in the body of the request. Credentials must be URL Encoded after they are base64 encoded
Consumer Application posts them to a designated URI (example: api.com/v1/user/accesstoken)
This request is signed using OAuth signing requests
The Service Provider will hand the Consumer Application back an Access Token
The Consumer Application will access the User's data using the Access Token