I'm trying to connect to Mojio REST api authenticated with OAuth2 with Python server code. Here's the 'manual' from Mojio: https://docs.moj.io/#/document/view/doc_oauth
I'm doing the second option there 'Authorization Code'. I don't understand what is the 'redirect_uri' parametr for. What should I pass there when I'm developing on localhost?
Thanks
You might want to consider using the "Resource Owner Password Credentials Grant" vs normal UI based oAuth workflows. This allows you to capture the username and password in your application and authenticate with those credentials instead of a UI (which can be challenging if you are on a server). Of course this depends on your specific requirements.
To login, via "Resource Owner" flow...
HTTP POST
Uri:
https://accounts.moj.io/oauth2/token
Body:
grant_type=password&username=USERNAME&password=PASSWORD&redirect_uri=REDIRECT_URI&client_id=CLIENTID&client_secret=CLIENTSECRET&scope=SCOPE
Content-Type:
application/x-www-form-urlencoded
This token you get back will be short lived, I would recommend getting a refresh token (longer lifetime):
To get a refresh token:
HTTP POST
Uri:
https://accounts.moj.io/oauth2/token
Body:
grant_type=refresh_token&refresh_token=API_TOKEN_YOU_GOT_FROM_LOGIN&redirect_uri=REDIRECT_URI&client_id=CLIENTID&client_secret=CLIENTSECRET
Content-Type:
application/x-www-form-urlencoded
Related
I have set up an API using configured with auth protected endpoints as described in this excellent tutorial
https://blog.miguelgrinberg.com/post/restful-authentication-with-flask
My end user, however, wants to authenticate by passing a JSON and then remain authenticated until the session expires.
The current method of authentication uses headers, as in the tutorial
$ curl -u miguel:python -i -X GET http://127.0.0.1:5000/api/resource
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 30
Server: Werkzeug/0.9.4 Python/2.7.3
Date: Thu, 28 Nov 2013 20:02:25 GMT
{
"data": "Hello, miguel!"
}
The users want to send the following instead
curl -L -X POST 'https://api.org/auth/?json={"client_id":"CLIENT ID","client_secret":"CLIENT SECRET","grant_type":"password"}' -H 'Content-Type: application/json'
There is clearly a way to authenticate once and remain authenticated because flask-restx endpoints display the attached image when you try to use an #auth.login_required decorated endpoint. Does anyone know what code this manual login code triggers and whether I can replicate the process by passing data received into an endpoint via JSON?
I have considered an internal redirect or curl-request but this seems unnecessarily clunky
manual login via API
The username/password prompt in your image is implemented by web browsers when the server uses the Basic Authentication method. If your client is not a web browser, then there is no user interface to request username and password, you have to implement that yourself.
Your assertion that "there is clearly a way" to authenticate and remain authenticated for the duration of the session is incorrect. The HTTP protocol is stateless, which means that every request stands on its own. You think that session authentication is possible because in some situations the data that you as a client are not providing is automatically inserted by the web browser or HTTP client. Examples:
When you log in to a website and then the website remembers who you are as you navigate from page to page, the browser is inserting a session cookie into all the requests that the client sends. The server writes information about the client in the session, so that it can recover it every time a request from the client is received.
When you use the username/password Basic Authentication solution that you referenced in your question, the browser saves the username and password that you entered, and inserts an Authorization header with them into all successive requests sent during the session. From the side of the server, every request comes with a username and a password and needs to be verified from scratch.
Finally, the JSON example that you show appears to be based on the OAuth protocol. This is a fairly extensive solution with many different flows. The one that you use in your example is the Password grant, in which the client passes username and password and receives an access token in exchange. This access token must be provided in all successive requests you make.
If your client application runs in the browser, then the two options that you have for the browser to help out with the authentication are:
Use session cookies. With Flask, this can be done with the Flask-Login extension.
Use Basic Authentication, to let the browser prompt the user for credentials, which are then automatically sent in successive requests. This is fully supported by the Flask-HTTPAuth.
I'm trying to authorise the API for Buffer (the social media scheduling app). I'm following the instructions here https://buffer.com/developers/api/oauth
The first step of the authorisation, redirects the user to an authorisation page using a request of the type:
GET https://bufferapp.com/oauth2/authorize?
client_id=...&
redirect_uri=...&
response_type=code
Once authorise the page redirects to the redirect_uri with the authorisation code as a query parameter:
http://example.com/back?code=1/mWot20jTwojsd00jFlaaR45
That code is then to be used in a POST request to obtain an access token:
POST https://api.bufferapp.com/1/oauth2/token.json
POST Data
client_id=...&
client_secret=...&
redirect_uri=...&
code=...&
grant_type=authorization_code
However, the authorisation code has a 30sec valid life.
When I do the authorisation manually and then a POST request with the auth_code I receive like so:
my_data = {
'client_id': my_client_id,
'client_secret': my_client_secret,
'redirect_uri': my_redirect_uri,
'code': auth_code,
'grant_type': 'authorization_code',
}
token = requests.post('https://api.bufferapp.com/1/oauth2/token.json', data=my_data)
I get an "invalid grant" error.
I looked up the error in relation to other APIs (Buffer API doesn't seem to be used that much) and one cause for it might be an expired auth_code. Which wouldn't be surprising given the short shelf life.
What's a good way to automate the authorisation bit to avoid expiration of the auth_code?
Or is it something else I'm doing wrong here?
Many thanks in advance for your help
Buffer is an OAuth 2.0 provider.
You have to use a OAuth 2 Workflow, read about
Requests-OAuthlib: OAuth 2 Workflow
The following sections provide some example code that demonstrates some of the possible OAuth2 flows you can use with requests-oauthlib. We provide four examples: one for each of the grant types defined by the OAuth2 RFC. These grant types (or workflows) are the Authorization Code Grant (or Web Application Flow), the Implicit Grant (or Mobile Application Flow), the Resource Owner Password Credentials Grant (or, more succinctly, the Legacy Application Flow), and the Client Credentials Grant (or Backend Application Flow).
I want to access an API endpoint which requires OpenAM authentication.
If I am trying to directly access this API endpoint, it will redirect (302) to OpenAM Auth page.
I am able to get a valid OpenAM token using https://github.com/jathanism/python-opensso.
But I am not getting how to use that valid token in-order to access the API endpoint.
I am trying to do this with Python.
If your API is protected by a policy agent, then the solution is simple, just include the session ID as a session cookie in the incoming request:
Cookie: iPlanetDirectoryPro=<sessionId-obtained-via-python-opensso
iPlanetDirectoryPro is the default name of the session cookie, it may be called differently in your environment.
I am using Flask-Restful to build a REST service. The iOS device will then connect to this REST backend to sync the local data.
The service will be accessed over a https connection.
The REST service is stateless and the user has to authenticate upon each request. Hence the username and password will be sent in clear format to the REST service. The backend will hash the password and check against the existing hashed password in the database.
api.add_resource(Records, '/rest/records/<string:email>/<string:password>/<string:ios_sync_timestamp>')
Now one problem I see with this approach is that the username and password are in clear format as part of the GET url. The server log will obviously track this. Now if my backend was ever hacked into, the log files would compromise all the usernames and passwords.
What is the best solution to this? I was thinking maybe sending username and password as POST arguments, but how do I that with GET requests then?
class Records(Resource):
def get(self, email, password, ios_sync_timestamp):
pass
def post(self, email, password, ios_sync_timestamp):
pass
To authenticate each requests with a username and password like you want, you should use: Basic Authentication.
To use it, it's pretty simple and it works with all HTTP methods (GET, POST, ...). You just need to add an HTTP header into the request:
Authorization: Basic <...>
The <...> part is the username:password encoded in base64.
For example, if your login is foo and your password is bar. The HTTP header should have this line:
`Authorization: Basic Zm9vOmJhcg==`
Through your HTTPS connection, it's secure.
EDIT: Using Flask, you can use Flask HTTP auth to achieve this "automatically".
Another solution instead of the Basic Auth in each call as suggested by Sandro Munda is to generate an API Key using a POST to first check credentials request and then passing it in the request headers. Then you can verify it in each API handler for a strict-grained checking or application-wide using a #before_request handler.
Workflow
Client sends a POST to the server with the credentials (username/pass)
Server replies with an API Key. Like an hexdigest of something secret.
from now on
Each time the client needs to send an API request it adds an header (let's call it X-API-Key with the API Key.
buddies
One of my GAE restful service needs login with admin account. And I'm writing an automation script in python for testing this service. The script simply do a HTTP POST and then check the returned response. The difficult part for me is how to authenticate the test script as an admin user.
I created an admin account for testing purpose. But I'm not sure how to use that account in my test script. Is there a way that my test script can use oath2 or other approach to authenticate itself as a test admin account?
Ok I think this might be what you are looking for, client libraries to authenticate and yeah I believe appengine now recommends using the oauth2 for any kind of authentication:
https://developers.google.com/accounts/docs/OAuth2#libraries
Then you get an auth token where you pass in headers on your restful request like:
# Your authenticated request
Authorization: Bearer TokenHere
Then in your handler you get it like:
try:
user = oauth.get_current_user('https://www.googleapis.com/auth/userinfo')
except NotAllowedError:
user = None
# then from the first link you should be able to access if
user.is_current_user_admin()
This is how I authenticate on android, but I only do this once and store it in session and just enable cookie jar on the httpclient.