How to securely store OAuth2 access and refresh tokens in Django - django

I'm trying to implement the Azure AD OAuth authentication for our Django app and I would be doing that with Azure AD as an OAuth provider. So now I wanted to know how securely we can store the OAuth access/refresh tokens in the DB that we receive from Azure AD or any OAuth provider.
I want to store the user's access token in DB because we have a feature in our web app where users can send an email with their email ID and we have a periodic job that runs every half an hour and it's gonna fetch user's mails based on a specific subject line. This we're gonna do with the help of Microsoft's Graph API and in order to call Microsoft Graph API, the web app should store the user's access token may be in the DB. But my concern is once we receive the access and refresh token, it shouldn't be accessed by anyone once we store it in the DB. So how securely or in an encrypted way we can store the OAuth2 access tokens in Django.
I have gone through a few articles, QnA, and forums on this concern but wanted to hear from the Django community as well.
Thanks in advance.

Let's start from sending email by graph(https://graph.microsoft.com/v1.0/users/{userId}/sendMail). I've done some test, here's the detail.
When I used credential flow to generate an access token, I can't use it to send email with an error like 'ErrorAccessDenied', it means that we can't generate a token that can be used for many accounts.
When I used auth code flow to generate an access token, I can't use it to send email when I set a different user id with the id that used to generate token in the api url. In this scenario, I also get the same error as above.
When I used ropc flow and I can send email successfully with it, this means I will send email successfully only when I used the correct user id and token.
Error message when failed to send email:
{
"error":{
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again."
}
}
And according to the test result, I think if you decide to store the tokens into the database, you can save it inline with the user id, so when your periodic job executed, your program can query for the correct token which could be decoded first to check if it is expired, and use it to send email.
If I misunderstand in some place, pls point my error out, thanks.

Related

API: How to secure access from non-related users?

I am developing a REST API. In my mobile application we have multiple user roles, they all use the same API. Think the roles are like customer, supplier, and admin. The API is using tokens, making sure everyone need to be logged in and should send the token to the API.
However, if someone has the token somehow, he can easily any information belong to any user. For an example, using the token of customer A, we can view the information of customer B, C` and so on.
Not only that, we can also access the API calls dedicated for the admins using the above mentioned token.
this is what I thought of doing.
Send the user ID with every request. Also embed the user ID into the token. In the server, before any method is accessed, check whether the user id in request and token are the same.
FYI I am using Firebase authentication and tokens, then use AWS API Gateway to authenticate the access to the API. The user Id I was referring to is in database.
How do you think I can overcome this issue and secure the API?
As long as you make sure to pass the tokens only over secured connections, interception of that token is not very likely. If you then use short-lived tokens (such as Firebase's ID tokens), even when a token does get intercepted it can only be used for a short amount of time.
If a token does get intercepted, you can revoke the token, as shown in the Firebase documentation on managing user sessions.
And finally, you can consider implementing App Check for an additional layer of protection, and check that token too in your own backend.

Handling the oauth token in a website/service

I have created a website which allows the user to authenticate against oauth2 (from another provider), the basic flow is (assuming a new user):
The user loads my webpage
An OAuth request token key and secret is provided by the OAuth endpoint
I store the request token into the user's cookies
The user is redirected to the OAuth authentication page from an external provider
The user accepts and is redirected by to my webpage with URL parameters which specify the OAuth verifier and OAuth token
Using the request token (retrieved from cookies) and OAuth verifier (passed via URL parameters), I am able to get an access token key and secret from the OAuth endpoint.
I am now able to authenticate with the providers API and use that to get the logged in user ID.
I then store into a MySQL database, the user ID, a token which I generate as a random unsigned integer, OAuth token and OAuth secret. In cases of the token I generate already being in the database, I just continue in a loop until a unique token is generated. The MySQL database has a strong name, username and password. The database user can only access the table in question and only has privileges to add an entry, delete an entry and make a query.
I clear the request token from the user's cookies and instead store the user ID and my generated token.
When a user comes back to my website, I check if they have the user ID and token stored in their cookies, if so I attempt to look up the OAuth token and secret from MySQL. If they are found, I test they are still valid (does the API endpoint accept them) and if so, the user remains 'logged in' to my website. In cases where the user ID or token isn't found in MySQL or cases where it is found, but is not accepted by the endpoint (expired?), I just go back through the flow above.
The above all works correctly, new users can successfully authenticate, returning users find the website remembers them. I do not expose the OAuth token key or secret to the user and instead, give the user this token ID which I generate.
Are there any problems with what I am doing?
Should I be encrypting the OAuth token key and secret in my database?
Is there a problem with the fact if someone was to gain access to the token I generate, along with the user ID, they would be able to call my scripts. Is this a problem?
Should I be encrypting the user ID and token I generate before storing it in the user's cookies? Taking into account, ultimately whatever is stored in the user's cookies will get passed to my script, so if I were to encrypt, store to cookies, then next time read from cookies and decrypt, the user would still be able to access my endpoints by simply passing the encrypted version (assuming the server decrypts, if the client decrypts then the decryption key would be accessible via the users browser anyway), which doesn't immediately appear to offer any further security.
My goal is to tighten up the steps above so it is deemed robust and secure. The actual use case for my web site means it'll only have a tiny number of users (if any) using it. It was more of a learning process for me, combined with implementing something I actually need. But for the learning aspect alone, I would like to make everything sensible and secure. I am not trying to be overly pedantic and implement steps no other similar websites would implement, basically I would like my site to be secure enough that if there ever was a problem, no one could point a finger at me and say I didn't implement an adequate security system.

Sending email (Office 365) using postman without logging in from browser

I would like to send an email on behalf of a user using Postman (Office 365). I have the email id and password of that account. After doing some research, I have found that I need to login, using a browser, to get the authorization code and then I can perform the next steps from Postman (getting the access token and using the Microsoft Graph Explorer) to send the email.
I would like to get the authorization code using Postman (not browser). I tried and got the following error (which is what should come the way I have requested the API)-
In short, I want to send email from Graph API using a REST client like Postman (right from authorization to sending email). Is this possible?
(I have already read these documents but did not help me get there-
https://developer.microsoft.com/en-us/graph/docs/concepts/rest
Accessing Microsoft Graph API without using login page
Automatically Log-In To Office 365
)
Yes, it is very possible, in fact, you can use all of the Microsoft Graph API from Postman or any other program which can make HTTP requests.
All you need to do is to get access token to use in your requests to the Graph API, and there at least 4 ways which allow you to do so without user interaction. But the process requires some preparation since you need to create an OAuth App in order to be able to use the Graph API.
Since I had to do the same myself and it wasn't easy to collect all the bits of information necessary, I've written a full guide on this subject including Postman examples:
Getting Access Token for Microsoft Graph Using OAuth REST API
In large you need to do the following steps:
Register OAuth App
Configuring App Permission
Use one of the following flows, depending on the information you have:
Flow 1: Get Access Token from Client Credentials (Client credentials Grant)
Flow 2 – Get Access Token From Client & User Credentials (Resource Owner Credentials Grant)
Flow 3 – Get Access Token From Refresh Token (Refresh Token Grant)
Flow 4 – Get Access Token From Another Access Token (On-Behalf-Of Grant)
Use the access token in requests to Microsoft Graph API
All of those steps are explained in the article.

How to make a pure JavaScript based Google or Facebook OAuth 2.0 secure to spoofing?

I am implementing JavaScript based Google or Facebook OAuth for a client login system, where I hope to use the Access Token and Email Id combination returned from Google/Facebook after successful authentication of the user to create session on the Server. I have a .NET based server application. I am hoping to send this Access Token and Email Id combination using some AJAX methods like $.ajax and creating a session for this email id on the server end.
Now I have a limitation, my server is behind a firewall and it cannot contact Google/Facebook to validate the access token.
One of my colleague pointed me out that as there is no communication between my Server and Google/Facebook, any malicious user can send me user A's email id with any random access token, and I have no way to check the validity of this token whether it actually belongs to User A.
My server is using SSL communication. So, how can I make this scenario secure.
I don’t think you should use a token you can’t validate. I don’t think your app can be run if you can’t contact IDPs to validate tokens. It’s a bit surprising, most firewalls let you call out, they don’t let others call in.
You could request an ID token as described here Cloud endpoints oauth2 error
This contains a signed user ID and email in a JWT.
This article might help https://support.zendesk.com/entries/23675367-Setting-up-single-sign-on-with-JWT-JSON-Web-Token-
disclaimer: I haven't tried any of this personally. Also, as Tim says, are you sure you can't call out from behind your firewall?

When adding Facebook integration to a web app, how do you handle OAuth token expiration and what user data should be saved?

I'm planning out adding Facebook integration to a web app I'm working on. For the most part, it's proceeding smoothly, but I am confused on the proper way to handle the OAuth token.
The sequence of events presented by Facebook here is:
Ask the user to authorize your application, which sends them to a Facebook window.
This will return an Authorization Code generated by Facebook
You then hit https://graph.facebook.com/oauth/access_token with your Authorization Code, which will give you a time-limited OAuth token.
Using the OAuth token, you can make requests to access the user's Facebook profile.
Facebook's documentation has the following to say about token expiration:
In addition to the access token (the access_token parameter), the response contains the number of seconds until the token expires (the expires parameter). Once the token expires, you will need to re-run the steps above to generate a new code and access_token, although if the user has already authorized your app, they will not be prompted to do so again. If your app needs an access token with an infinite expiry time (perhaps to take actions on the user's behalf after they are not using your app), you can request the offline_access permission.
When they say to re-run the steps above, what steps need to be re-run to get a new OAuth token? What data (Facebook UID, Authorization Code, OAuth token) does it make sense to save to my local database?
I would like to be able to have the user continue to interact with my site, and in response to certain user actions, I would like to be able to prompt to user if they want to post something to their Facebook wall.
The access token is time and session based and is unnecessary data to store and have no use after the user have closed the session.
The facebook uid is the only thing you need to identify the user.
Since the Facebook API sometimes is horrible slow you could store the username aswell.
But for identification, all you need is the uid.
The documentation that facebook provides has been updated since you asked this question. https://developers.facebook.com/docs/authentication/.