Securing a web app against authorization API without revealing credentials - node.js

I have a web app MyWebApp.
And two APIs: MyAuthAPI and MyServiceAPI, both RESTful NodeJS. MyAuthAPI uses HashiCorp Vault as a token store with OAuth2.
MyServiceAPI has CRUD operations available to authenticated clients.
There is no human login required (or desired) on MyWebApp. Any human can access MyWebApp through a browser and run the service.
At present, this is the (very insecure) flow:
MyWebApp sends clientid and clientsecret to MyAuthAPI to retrieve token. This token is then used for communicating with MyServiceAPI.
The obvious downside is that anyone can capture the clientid and clientsecret by simply looking in developer tools in a web browser. They could then use those to authenticate with MyAuthAPI, generate their own token, and make calls to MyServiceAPI without MyWebApp being involved.
So how do I best secure the entire application so that MyWebApp is safely and robustly authenticated without revealing the credentials?
Thanks.
ETA:
I want to be able to authenticate MyWebApp with MyAuthAPI and then use the generated token to connect to MyServiceAPI. But I don't want it to be possible that anyone can intercept those credentials - currently they can be see in the request header as "Authorization: Basic "
The MyServiceAPI endpoints must be secured so that only authenticated clients are able to access them. But when that client (MyWebApp) is a public website, how do I authenticate without making the credentials visible?
ETA2:
https://mywebapp.com is MyWebApp which is a React application.
https://myauthapi.com hosts MyAuthAPI
https://myserviceapi.com hosts MyServiceAPI
When I load mywebapp.com in a web browser, it authenticates with myauthapi.com/oauth/token to get a token. At present it does this by sending the creds in the header Authorization: Basic
The token that is returned is then saved.
The web application then tries to get the data from an endpoint on MyServiceApi using this token:
Authorization: Bearer
GET https://myserviceapi.com/objects
or POST myserviceapi.com/objects
or GET myserviceapi.com/objects/objectid
or DELETE myserviceapi.com/objects/objectid
MyServiceAPI verifies the token with MyAuthAPI, but that isn't public-facing, so there's no issue there.
The issue is that, as you can see from the attached screenshot of the Developer Tools console in Chrome, anyone using the web application can see the Authorization header containing the credentials, and could then use these credentials to programatically gain access to the auth API to generate a token which can then be used on the service API endpoints.
I want to restrict all access to the API servers to only come from specific applications, such as MyWebApp, on mywebapp.com.

First, I think this question could better be asked in https://softwareengineering.stackexchange.com/.
Second, where MyWebApp is deployed? How it is being used? If it works with https, then the body is encrypted, and when you send the clientId and clientSecret, you should send it in the body, so users will not be able to see them.

Client Credentials Grant should only be used by confidential Clients. Thats because you can't hide the client_secret on non confidential Clients. Your frontend seems to be a non confidential Client.
Normally you should use the Authorization Code Grant with PKCE. But you would need users to authenticate themselves for that.

Feels like you need an architecture design based on standard flows, since OAuth should work like this:
Web app signs user in via an Authorization Server, using Authorization Code Flow (PKCE)
Web app gets tokens from the Authorization Server
Web app calls API with an access token
API validates token using data from the Authorization Server
API then trusts claims in the access token and uses them for authorization
See my Initial HTTP Messages blog post for an example of how this looks.

Related

How can I use azure ad access token which is got from SPA to protect backend api?

I want to use azure AD as authentication.
If user who is in certain organization logged in from SPA, and give access token to backend, then I want to permit access from SPA.
So, I want to check if token passed from SPA is valid or not.
How can I do this?, Or Can I do this?
I want to build backend server with node.js app, and deploy backend app to app service or Azure Container Registry.
I think bearerStrategy would work.
Ref https://github.com/AzureAD/passport-azure-ad
BearerStrategy uses Bearer Token protocol to protect web resource/api.
It works in the following manner: User sends a request to the
protected web api which contains an access_token in either the
authorization header or body. Passport extracts and validates the
access_token, and propagates the claims in access_token to the verify
callback and let the framework finish the remaining authentication
procedure. On successful authentication, passport adds the user
information to req.user and passes it to the next middleware, which is
usually the business logic of the web resource/api. In case of error,
passport sends back an unauthorized response.
In the past, there was an ADAL version for node apps. I don't know if it's still valid or not, but here are useful links:
https://medium.com/#liangjunjiang/verify-and-decode-azure-activity-directory-token-bc72cf7010bc
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-flows-app-scenarios

what can we do with instagram's access token?

I started working with instagram APIs using node.js and walked through the official instagram API docs here but it does not explain clearly.
Here I have 2 questions:
what is the difference between Client ID and Client Secret?
what is access_token ? and what is it used for ? and
when we should request for it ?
The client ID is is basically a unique id assigned to your application by an Oauth provider. It considered public information, and is used to build login URLs, or included in Javascript source code on a page.
An app requesting an access token has to know the client secret in order to gain the token. This prevents malicious apps from ever obtaining a valid access token. The client secret id doesn't state anything about authenticating a user, but it's instead for authorising an app to request access tokens.
The client secret must be kept confidential. If a deployed app cannot keep the secret confidential, such as single-page Javascript apps or native apps, then the secret is not used.
When you login with an Oauth provider, the server responds with an access token and expiration time in ms if the login is successful.
{
"access_token":"RsT5OjbzRn430zqMLgV3Ia",
"expires_in":3600
}
Every time client requests a resource from the server, the server validates the access code. The access-token is used to verify every request from the client. You will request for an access_token whenever you login through an Oauth provider.
You can refer this and this for more information.

Should my app issue it's own access tokens, when using external oauth2 provider (facebook)?

I would like to give the users a possibility to login with some external oauth2 provider (facebook) in my app. The client's part is running on mobile device in a native app.
I am not sure which of the approaches below should I prefer ?
Should the client send the user's access token by facebook with each request ? At each request backend asks facebook to validate the access token. Based on the validation's result, backend performs authorization and return corresponding result to the client.
Should the backend ask facebook to validate the access token only at user logon, then issue its own access token, return the access token back to the client and client will use this access token at making requests to the server to avoid contacting facebook at each request ?
I have read some questions about how to implement the auth with facebook and most of the devs are using B, but I haven't seen any explanation why is it good/bad to use A ?
What I see as benefits of the solutions:
backend doesn't need to care about issuing, refreshing, validating access tokens since this is done only by facebook's authorization servers.
this solution seems to be more effective, since it does not require to connect to facebook at each request.
Security tokens issued by Facebook are signed with a digital signature. The API server only needs access to the public key to validate the signature. There's no need at all to contact Facebook after the user authenticates.
A reason to issue your own tokens after the user signed in with Facebook could be to add claims to the token. But obviously having your own authorization server comes at a cost. It's up to you to weigh the pros and cons.
If you do decide to have your own authorization server, make sure not to write your own! There are open source options like Thinktecture IdentityServer.
I will vote for option B and here is my explanation,
Your API must authorise the request every time with some auth token , which cannot be external provider token, in such case anyone with an access token (eg: other developers) of other provider can access your api, basically there is no auth here.
When your sever issue access token, it's easy to validate and when needed could be revoked easily (eg: on password reset)
While authenticating , your server has fully control over issuing access token , so the validation is made only once and doesn't have to do every time while calling the API.

Authentication with React Native and API backend

I'm trying to wrap my head around oauth with a React Native app and a separate NodeJS/Express API backend. I understand https://github.com/adamjmcgrath/react-native-simple-auth offers authentication for a React Native app and http://passportjs.org/ offers authentication for a NodeJS backend. I'm unsure how to connect these two for authentication for login and access to the API.
I'd like users to login to the React Native app either by email and password or via Facebook/Twitter/Google. Once logged into the app, what do I send to the API to make sure they are authenticated and have access to a specific route?
Here is an example flow to login and see the logged-in user's settings:
User logs into React Native app via email/password or Facebook/Twitter/Google.
User is authenticated
App makes request to GET /api/settings
API verifies user is authenticated and returns that user's settings or API verifies user is not authenticated and returns a 403.
There's a whole lot to this question, so much so that it wouldn't all fit in a single SO answer, but here's some tips and a general outline that should broadly fit into what you want to accomplish.
OAuth2 Authorization
From the sounds of it, you are interested in using OAuth 2 to provide social login authorization, and would like to do first-party authentication as an alternative with an email and password. For social logins you will end up using the OAuth 2 Implicit flow to retrieve an access token, which is a widely recognized pattern. Because you are also looking to authenticate users with an email and password, you may want to familiarize yourself with OpenID Connect, which is an extension of OAuth 2 and which explicitly supports authentication in addition to authorization.
In either case, once your user has either submitted an email/password combo or granted permission through the social identity providers, you will receive in response an access token and (optionally) an ID token. The tokens, likely a JWT (JSON Web Token, see jwt.io) will come across as a base64 encoded string that you can decode to inspect the results of the JWT, which will include things like the ID of the user and other details like email address, name, etc.
For more info on the different types of flows, see this excellent overview on Digital Ocean.
Using Tokens for API Authentication
Now that you have an access token, you can pass it along with all requests to your API to demonstrate that you have properly authenticated. You'll do this by passing along the access token in your HTTP headers, specifically the Authorization header, prefacing your base64-encoded access token (what you originally received in response to your authorization request) with Bearer . So the header looks something like this:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh...
On your API's side, you will receive that token, decode it, and then verify the ID and claims in it. Passed as part of the token in the sub property will be the subject, or ID of the user making the request. This is how you identify access and start to do things on your API side with the respective user's rights, perms, etc. It is also important that you validate the access token once you receive it on your API side, to ensure it wasn't spoofed or hand-crafted.
How it looks in RN for Implicit flows
Here's what the general process looks like in React Native for OAuth 2 Implicit flows, which is what you'll use for social identity providers:
User taps one of your social login buttons on React Native UI
Your code that responds to the buttons will build a request URL to those providers, depending on what each wants (because it differs slightly).
Using the Linking API in RN, you will open up that URL in a browser on the device which sends the user off to the social provider for them to do the login/authorization dance.
Once complete, the social provider will redirect the user to a URL you provider. On a mobile device, you will use your own custom URL scheme to move the user from the web view to your app. This scheme is something you register as part of your app, such as my-awesome-app://, and the redirect URL you pass to the social provider could look like my-awesome-app://auth_complete/. See the Linking API docs for how to configure these URL schemes and deep linking.
In the handler for that new URL scheme/deep link, you'll get the tokens passed as part of the URL. Either by hand or using a library, parse out the tokens from the URL and store them in your app. It's at this point that you can start inspecting them as JWTs, and pass them along in the HTTP headers for API access.
How it looks in RN for Resource Owner Password Grant flows
You have the option for your email/password combo for your own accounts of either sticking with the Implicit flow, or switching to the Resource Owner Password Grant flow if your API and app are trusted by each other, meaning that you are making both the app and the API. I prefer the ROPG flow on mobile apps where possible because the UX is much nicer--you don't have to open up a separate web view, you just have them type in their email and password into UI elements directly in the app. So that being said, here's what it looks like:
User taps the email/password combo login button, and RN responds with a UI that includes TextInputs for the email and password
Build a POST request to your authorization server (which may be your API, or may be a separate server) that includes the properly crafted URL and body details that passes along the email and password. Fire this request.
The auth server will respond with the associated tokens in the response body. At this point you can do the same thing previously done in step 5 above, where you store the tokens for later use in API requests and inspect them for relevant user information.
As you can see, the ROPG is more straightforward, but should only be used in highly trusted scenarios.
At the API
On the API side, you inspect for the token in the Authorization header, and as mentioned previously, and if found you assume that the user has been authenticated. It is still good security practice to valid and verify the token and user permissions. If there is no token sent with the request, or if the token sent has expired, then you reject the request.
There's certainly a ton to it, but that provides a general outline.

Using OAuth instead of Basic authentication?

We have a web service, which currently uses Basic Auth over https to authenticate user requests. We also have a website which uses the service, and a native Windows client, which also uses the web service. I've read about OAuth, and it seems like it's always used for giving or getting access to external resources, i.e. delegation, but I'm trying to understand if it's a replacement for Basic Auth.
I'm not quite sure how all the parts fit together. Do you use Basic over https to the website to retrieve a secret and then have the javascript which is making requests to the REST services authenticate to the web service using OAuth instead of Basic?
It seems that at some point the user needs to enter their username and password into a form. I'm not sure what typically happens next. Is this even a use case for OAuth?
If you have local database accounts for the users (Resource owners) then you can replace the basic authentication with the one of OAuth flow named "Resource Owner Password Credentials" flow.
It is very simple flow where you issue HTTP post to an end point specified in your HTTP server usually named /token The content-type for this HTTP Post action is x-www-form-urlencoded, so the post body will contain something like this grant_type=password&username=Taiseer&password=SuperPass
One the request is sent to the /token end point the server will validate the user credentials against your database store, and if all is valid it should generate a token (signed string) which contains all the claims for this resource owner (user). Then your client application should present this token in the Authorization header with each call to any protected end point using bearer scheme.
This token expires after certain period and you can configure this from the AuthZ server. You can read my detailed blog post Token Based Authentication to get more details.

Resources