I'm using OAuthToolkit and DjangoRestSwagger. I've created an application using Django Admin, and now I've client_id and client_secret.
I want to generate the token using client_id and client_secret. Currently, I use curl to generate the token.
curl -X POST -d "grant_type=client_credentials" -u"client_id:client_secret" http://localhost:8000/o/token/
How can I do it using the Swagger docs.? Basically, how can integrate third party(OAuthToolkit) API URLs with Swagger?
Currently, I've an Authorize button which takes api_key value, ie the token.
Here's my Swagger settings.
SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'token': {
'type': 'apiKey',
'name': 'AUTHORIZATION',
'in': 'header',
}
},
}
Not certain about django-rest-swagger but if you are looking for an alternative with gauranteed support for oauth you can use drf-yasg (yet another swagger generator)
Documentation for yasg adding oauth paths to swagger
Related
I'm looking to propagate a JWT token between my services running in docker using the library flask-jwt-extended and I have an idea of how I would do this using something similar to this:
request.post(url, json={"access_token": access_token, "refresh_token": refresh_token)
But in my experience I need to return a response to do this.
I already have the frontend creating tokens and protecting my routes. I just want to use that token to do the same for the backend.
I want to be able to login from my frontend application and when I login that propagates the token throughout the other services. How do I approach this?
I will send the post request to a function that will look something similar to this:
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == "POST":
resp = jsonify({'login': True})
set_access_cookies(resp, request.json["access_token"])
set_refresh_cookies(resp, request.json["refresh_token"])
return resp, 200
Do I need to return that response?
Token sharing should be accomplished via signature trust. Make sure that your other services "know" the public key of the trusted signer.
Here's the basics:
Frontend requests token from backend via authorization api
Backend validates credentials, issues token using 'RSXXX' algorithm, eg. 'RS512'
Frontend passes token to all calls to any of your backend services.
When backend receives a token it verifies signature and "source" using the public key identity of the token before applying token payload to the requested operation.
All backend services and the frontend should have a configuration element which defines one or more trusted public keys used for token signing.
This article has some helpful information on using a public/private key pair with pyjwt:
https://blog.miguelgrinberg.com/post/json-web-tokens-with-public-key-signatures
So, i new in django and djangorestframework. i followed their tutorial in their page. http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/
in that tutorial, you can login as django user from djangorestframework api login page. my question is, if i want to make a CLI or GUI application and using requests module to post a content to the API, but the API must be loggged in first. how i do that?
In DRF, you can add additional package for simple token-based Authentication. Add rest_framework.authtoken to INSTALLED_APPS. To make HTTP(S) request to client you pass the authorization token like this Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
For testing, you can use curl
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Read more...
You can set that a user must be authenticated at all times as default setting in settings.py (in your web server project):
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
More info about that here.
In your web client project, like one of the comments on your questions mentions, you must add an Authentication header in the HTTP messages you send to the web server. An example (TypeScript Angular application implementation) would be:
import {Injectable} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {Spacecraft} from '../model/spacecraft';
/* Create the authentication headers for the HTTP requests to the DRF project's API.
* Note: uses btoa(): base-64 encoding of ASCII string, see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa.
*/
const basicAuthenticationToken = btoa(environment.REST_API.username + ':' + environment.REST_API.password);
const httpOptions = {
headers: new HttpHeaders({
'Authorization': `Basic ${basicAuthenticationToken}`
})
};
#Injectable()
export class APICommunicationService {
constructor(private http: HttpClient,
private notificationsService: NotificationsService) {
}
getSpacecraftInfo(url: string): Observable<Spacecraft> {
return this.http.get<Spacecraft>(url, httpOptions)
}
}
I want to send data through a post request but only those who are authenticated can do it. In django application I added the BasicAuthentication in settings.py
...
REST_FRAMEWORK = {
'PAGE_SIZE': 10,
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
)
}
and in Qt post authenticated to do so
...
QNetworkRequest request;
QUrl url("https://.../data/");
url.setUserInfo("username:password");
request.setUrl(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QString json = QString(...);
QNetworkReply *reply = m_manager->post(request, json.toUtf8());
...
As an error the server returns me -> Error transferring https://username:password#.../data/ - server replied: Bad Request.
I can not understand whether the problem lies in the way in which pass username: password or django app.
Set user info just appends the "username:password" to the URL authority section. See the docs for an example. For HTTP basic authentication, you need to use something similar to this answer.
I know to logout user in Django. If i want to logout user, i would do
from django.contrib.auth import logout
def logout_view(request):
logout(request)
But what is the relevant way of logging out the user if i am using django oauth toolkit(DOT)?
Should i follow the same or delete the token? Some says delete the token and some says expiry period should be expired. Please provide me the best possible resolution for logging out in DRF using DOT.
You can check Revoking an OAuth2 Token
You’ve granted a user an Access Token, following part 1 and now you would like to revoke that token, probably in response to a client request (to logout).
And Do you logout a user who login via OAuth2 by expiring their Access Token?
EDIT
# OAuth2 provider endpoints
oauth2_endpoint_views = [
url(r'^authorize/$', oauth2_views.AuthorizationView.as_view(), name="authorize"),
url(r'^token/$', oauth2_views.TokenView.as_view(), name="token"),
url(r'^revoke-token/$', oauth2_views.RevokeTokenView.as_view(), name="revoke-token"),
]
If you follow the tutorial part2 you will find you already have the revoke-token url, so you just need to send request to this url.
EDIT2
Let me try to explain this clearly
When you use Django OAuth Toolkit and DRF, you usually will use
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
)
}
And you can get access token by
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
And get response like this
{
"access_token": "<your_access_token>",
"token_type": "Bearer",
"expires_in": 36000,
"refresh_token": "<your_refresh_token>",
"scope": "read write groups"
}
Now you can use your access_token to request the api you set like this
curl -H "Authorization: Bearer <your_access_token>" http://localhost:8000/users/1/
How to logout depends on how you define login
Website define login from the session in cookies. When you developing a mobile app, You will define login depend on message in your app (user credentials present in keychain or not when it comes to IOS), and that is what your code do:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
You can see source code here django-logout and docs here
flush()
Deletes the current session data from the session and deletes the session cookie. This is used if you want to ensure that the previous session data can’t be accessed again from the user’s browser (for example, the django.contrib.auth.logout() function calls it).
But remember, From Luke Taylor
The lifetime of the access_token is independent of the login session of a user who grants access to a client. OAuth2 has no concept of a user login or logout, or a session, so the fact that you expect a logout to revoke a token, would seem to indicate that you're misunderstanding how OAuth2 works. You should probably clarify in your question why you want things to work this way and why you need OAuth.
Finally In your case, I think you need to revoeke the token before logout:
def revoke-token(request):
# just make a request here
# POST /o/revoke_token/ HTTP/1.1 Content-Type: application/x-www-form-urlencoded token=XXXX&client_id=XXXX&client_secret=XXXX
def logout(request):
response = revoke-toke(request)
# if succeed
logout(request)
I have a django project, using django-rest-framework to create api.
Want to use token base authentication system so api call for (put, post, delete) will only execute for authorized user.
I installed 'rest_framework.authtoken' and created token for each users.
So, now from django.contrib.auth.backends authenticate, it returns user, with auth_token as attribute. (when loged in successfully).
Now my question is how can I send the token with post request to my api and
at api side how can I verify if token is valid and belongs to the correct user?
Are there any methods in app rest_framework.authtoken to validate given user and its token?
not found this very useful!
Update (changes I made):
Added this in my settings.py:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
Also sending Token in my header but its still not working:
if new_form.is_valid:
payload= {"createNewUser":
{ "users": request.POST["newusers"],
"email": request.POST["newemail"]
}
}
headers = {'content-type' : 'application/json',
'Authorization': 'Token 6b929e47f278068fe6ac8235cda09707a3aa7ba1'}
r = requests.post('http://localhost:8000/api/v1.0/user_list',
data=json.dumps(payload),
headers=headers, verify=False)
"how can I send the token with post request to my api"
From the docs...
For clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
"at api side how can I verify if token is valid and belongs to the correct user?"
You don't need to do anything, just access request.user to return the authenticated user - REST framework will deal with returning a '401 Unauthorized' response to any incorrect authentication.
To answer the first half of your question:
how can I send the token with post request to my api
You can use the Python requests library. For the django-rest-framework TokenAuthentication, the token needs to be passed in the header and prefixed by the string Token (see here):
import requests
mytoken = "4652400bd6c3df8eaa360d26560ab59c81e0a164"
myurl = "http://localhost:8000/api/user_list"
# A get request (json example):
response = requests.get(myurl, headers={'Authorization': 'Token {}'.format(mytoken)})
data = response.json()
# A post request:
data = { < your post data >}
requests.post(myurl, data=data, headers={'Authorization': 'Token {}'.format(mytoken)})
I finally have the django "rest-auth" package working for token authentication.
If this helps, here is the client-side jQuery code that worked for me, after you successfully log in and receive the "auth_token":
var user_url = {API URL}/rest-auth/login
var auth_headers = {
Authorization: 'Token ' + auth_token
}
var user_ajax_obj = {
url : user_url,
dataType : 'json',
headers: auth_headers,
success : function(data) {
console.log('authorized user returned');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
console.log('error returned from ' + user_url);
}
};
$.ajax(
user_ajax_obj
);
If you are using coreapi. To add the Authorisation you do
import coreapi
auth = coreapi.auth.TokenAuthentication(scheme='Token', token=token_key)
Then you can do
client = coreapi.Client(auth=auth)
response = client.get(my_url)