How to cache auth token with chrome.identity.launchWebAuthFlow? - google-chrome-extension

I'm using chrome.identity.launchWebAuthFlow method to initiate a OAuth2 token generation from our OAuth2 server.
In the Identity API documentation, it is specified that to authenticate a user, there are two available methods: getAuthToken and launchWebAuthFlow. We use the latter because as specified in the documentation:
If your app uses its own server to authenticate users, you will need to use launchWebAuthFlow.
We're struggling to cache the results. When reading the documentation of getAuthToken, it seems that there is some smart-caching involved.
Chrome catches the response and store the access_token and renew_token in the browser (visible here: chrome://identity-internals/). Chrome requests for an access_token to the OAuth server only when the access_token is expired.
However, using launchWebAuthFlow, we're struggling to use the Chrome Cache, and it calls our OAuth server each time.
Does anyone know how to cache the result using this method of the API?

getAuthToken only refers to authenticating with Google's own apis, if you want to do similar stuff yourself you'll have to implement it yourself.
Simply use chrome.storage to store the incoming credentials and when they are used, then only fire launchWebAuthFlow if enough time has passed, else make the fetch call anyway and if it comes back unauthenticated then refresh your token

Related

How to handle multiple IDP with opaque access tokens

I am currently writing a social media backend server, which should handle a lot of users.
As authentication mechanism, we want to use Google's & Apple's OIDC Authentication (Sign in with Apple).
Now, as we get a opaque access token, I cant really imagine a performant way to authorize the opaque access token, as we can not decode the token (not jwt token) and we do not know the issuer.
What I thought:
Authorize the access token sequentially one by one. Meaning:
Fetch Google/userinfo from Google
If 401, Fetch Apple/userinfo
This is unperformant, as the processing time is getting bigger, when we add more IDP's
Save the issuer in the DB and fetch the user's issuer always in the authentication step, before fetching the /userinfo endpoint
This is more performant, but it does not feel right, as the webserver has to make a DB call + HTTP call to authorize a request from the client.
Am I missing a method to get this in a performant way?
BTW: The webserver is a node.js application using express.js
Thank you very much in advice!
The key point here is that foreign access tokens are not designed for authorization in your own back end. Instead you need to issue your own tokens when sign in completes.
AUTHORIZATION SERVER (AS)
The most standard solution is for your apps to talk to an AS that you own, and for it to manage the social logins for you. The AS will then issue tokens that you can fully customize.
This will enable you to fully control the scopes and claims your back end uses for authorization, as well as the session times in UIs. Your back end will only ever work with access tokens issued by the AS, regardless of the login method a user selects.
When you need to add a new login method you just change the AS configuration and will not need to change any code in your apps. A good AS will support integrating with many systems, as demonstrated in this summary page.

Authentication with JWT in React and Node-Express using Github OAuth

I have been trying to implement Google and Github OAuth authentication in one of my projects which uses React on the client side and NodeJS-Express on the backend. After going through dozens of articles and several Youtube videos later, here's what I have discovered about OAuth.
There are two main flows in OAuth. Authorization Code Grant Flow and Implicit Flow. To be on the same page, I would elaborate what I understood about both of these flows in short:
Authorization Code Grant Flow : User(resource owner) clicks on Login with Google/Github and is then redirected to the consent screen. Once they give consent, user(resource owner) is redirected back to the callback_url with a authorization_code in the URL query parameter. The authorization code is then send to the backend server. The server then makes a request to the authorization server of the OAuth provider along with the client_id,client_secret and the authorization code and then receives a access_token as well as a refresh_token required to access the resource server.
Implicit Flow : It is sort of a hacky way that was proposed back in the day for Single Page Applications as CORS wasn't properly implemented in all the browsers. Here the Single Page Application is given the access_token once the resource owner has given consent to the OAuth provider and it is now the duty of the SPA to store the access_token in a protected manner. However, since browsers aren't really trustworthy, and CORS is a real thing now, the Implicit flow is not really recommended anymore.If someone wants to implement the Implicit FLow, PKCE (Proof Key for Code Exchange) is sort of the standard now.
What I tried to implement
I decided to go ahead with Authorization Code Grant Flow as it seemed the most secure to me and also I have a backend server to handle the authorization code exchange.
Here is what most people suggest in order to implement Authorization Code Grant Flow with React.
Render a link like this.
<a href='http://localhost:8000/auth'>Login With Github</a>
Now handle this endpoint in the backend
app.get('/auth',(req,res)=>{
res.redirect(githubOAuthConsentScreenURL)
})
Now handle the redirect_uri in the backend and make a post request to the authorization server to get a access_token
app.get('/auth/callback',(req,res)=>{
//Extract the authorization code from query params and make a POST request to get back the access_token
})
Passport JS also implements this approach which is handling the callback url on the server.
Here is what I thought of doing:
Handle the callback URL on client side i.e. with React. Extract the authorization code from the parameters and then make a XHR call to the server with it. The server will now exchange the authorization code for an access_token and make a request to get the user's profile data. If everything succeeds, the Express backend will return a short lived access_token and a long lived refresh_token which will then be used by the React application to access the REST API.
My question here is : Which method is correct and the standard way to do authentication, handling the callback_url on the server or on the client side?. The method I propose over here seems more logical to me. Does my method have any security flaws compared to the other one? Am I missing something?
Other things that I have confusions about :
How is OAuth vulnerable to CSRF? From what I read, the state parameter can be used to protect the OAuth flow against CSRF. However, if I am redirecting the user from my backend server and then handling the callback_url in the server as well, how do I remember the state variable apart from storing it in some sort of session/db. Is it not more logical to redirect the user from the browser? Then the state parameter can be stored in the localStorage and can be matched later during the callback.
Also, I am implementing a short lived access_token and a long lived refresh_token for authentication and storing both the tokens as httpOnly cookie. If my access_token is stored as a httpOnly cookie, then how do I know if I am logged in or not and persist the state in React. One solution (proposed by Ben Awad in this video) was to query for the user during initial load and if the query succeeds, store the state (maybe in Redux) and then conditionally render the routes.
Is this the correct way of doing this? If not what is the standard manner that is followed by React applications which are actually in production? Again, am I missing something here?
Please Note : I am pretty new to authentication, would appreciate all the help and detailed explanations.

Should I make 3rd party API calls in backend or frontend?

I have an API and that API needs some data from the Microsft Graph API. I was thinking of implementing an endpoint in my API to refresh the token and use that token to make calls from the frontend. I don't know if that's optimal or safe, hence my question.
EDIT 1: To give a better perspective of what I have, this is the logic I have at the moment. Tell me if this is correct please.
User requests my API's authorization endpoint, which has the Azure's secret key, then the user is redirected to the Microsft oAuth login page. Once logged in oAuth, Microsoft redirects the user to my API, where it saves the JWT tokens in the user's cookies, so the user can refresh the token anytime.
In order to refresh the token, the user simply just makes a call to myapi.com/auth/microsoft/token, where it has the secret key, and it refreshes.
Generally I would recommend always making the 3rd party calls from the back end. It gives you more control and avoids any cross origin complications.
You also want to be aware of any API keys. Most APIs require a key for access and often that key is private and you wouldn't want to share on the front end.
MS Azure APIs have an application and secret token. You cannot expose the secret token to the client. To call directly from the client you would use OAuth to get a JWT token and then you can call from the SPA into the MS Web APIs with that token.
https://learn.microsoft.com/en-us/azure/active-directory/develop/authentication-scenarios#single-page-application-spa
In contrast, there are other 3rd party APIs that are designed to be called only from the front-end. Stripe for example is a payment processing API where the UI can call directly into Stripe and then the client's payment information is never actually passed to the host application, only to Stripe. This improves security.

What are the recommended strategies for authorising API calls from my react native application to my node server?

I have a react native application that I want to make API calls from. I am getting confused about how I should be authorising these calls on the node back end.
Method 1:
User logs in to application and authenticates, I then return a JWT with refresh token. This is then stored client side / in react native app and is sent upon each request. If token expires, then refresh using refresh token.
Method 2:
Create API key for each client. When a user creates an account, I create an API key (or maybe access key and secret key like AWS does) and send that with each request.
Is there a preferred / recommend method out of these two? Perhaps they are not mutually exclusive? Do I still need to provide an API key to my react native app so that it can make API calls and then I use JWT for authenticating users?
In my personal opinion,
You may go for the Method 1, since it is not secure to store / create API keys or Secret keys on the client side.
JWT are more secure, you may read the following article
In the Method 2, you will most probably try this approach
Generate Api key based on client IP or the device token, whatever suits you, and set an expiration time including the AES techniques, then decrypt it on the server, check the client's IP against the requestor IP and also the expiration time.
Complexity and time taken to do Method 2 is much more that Method 1, also considering I might have not covered all the security use cases.
Do I still need to provide an API key to my react native app so that it can make API calls and then I use JWT for authenticating users
You can make the http calls normally. The recommended way is call your token generation api and then authenticate other valuable api's based on that token if you're using JWT
Hope it helps.

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.

Resources