Comments (15)
I have been able to integrate it easily in a few places, initially i followed the GlobalAuth example in the docs here by extending the HttpBearer class like so and using the JWTAuthentication class from the simplejwt library, like so:
from typing import Any, Optional
from django.http import HttpRequest
from ninja.security import HttpBearer
from rest_framework_simplejwt.authentication import JWTAuthentication
class JWTAuthRequired(HttpBearer):
def authenticate(self, request: HttpRequest, token: str) -> Optional[Any]:
jwt_authenticator = JWTAuthentication()
try:
response = jwt_authenticator.authenticate(request)
if response is not None:
return True # 200 OK
return False # 401
except Exception:
# Any exception we want it to return False i.e 401
return False
As for the creation of tokens, its a fairly simple approach also. I have 2 schemas one for the auth and one for the repsonse:
from ninja import Schema
class AuthSchema(Schema):
username: str
password: str
class JWTPairSchema(Schema):
refresh: str
access: str
These are then used in my authentication router like so:
from ninja import Router
from auth.api.schema import AuthSchema, JWTPairSchema
from django.contrib.auth import authenticate
from rest_framework_simplejwt.tokens import RefreshToken
router = Router()
@router.post('/login', response=JWTPairSchema, auth=None)
def login(request, auth: AuthSchema):
user = authenticate(**auth.dict())
if user is not None:
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
I have reused all my authentication logic from DRF in django-ninja and it works well. Hope that helps someone else.
from django-ninja.
Hi @vitalik!
Any news?
from django-ninja.
it is not out of the box, but (as it actually requested few more time) I will try to pull out some example into separate repository as a plugin
from django-ninja.
@VetalM84
Hey, I'm the author of that comment in the reddit thread. As far as I can tell you managed to get it to work now, but if you have any more problems let me know and I'll try to help.
I am building a pretty large enterprise app and this auth method has been happily working for me for a year now.
from django-ninja.
Hey,
if you have set up your sign in endpoint to send urlencoded data (and set up parameters as form data with something like username: str = Form(...), password: str = Form(...)
than you would have to set up your test something like this:
data = f"username={username}&password={password}"
response = client.post(f"{API_ROOT}/auth/sign_in", data=data, content_type="application/x-www-form-urlencoded")
I have since switched my sign in endpoint to expect the usual json post request where I'm sending username and password in json, so then the test would be like yours, only content_type would be = "application/json"
from django-ninja.
I was having the same question... Since JWT is just another form of bearer authentication what about this? I'm using python-jose for the JWT.
from jose import jwt
[...]
class JWT(HttpBearer):
def authenticate(self, request, token):
try:
jwt.decode(token, 'key')
return True
except:
return False
[...]
@router.get('/', auth=JWT())
This works just fine.
EDIT: Somehow it only worked when using Django's development server and didn't translate to the productive environment. God knows why but it's already too late for me to think properly. I fiddled around with it even more, another solution at least within a development setting is:
def validate_jwt(request):
token = request.META['HTTP_AUTHORIZATION'].split(" ")[1]
try:
jwt.decode(token, 'key')
return True
except:
return False
[...]
@router.get('/', auth=validate_jwt)
But this also sucks. I will look into it tomorrow.
EDIT 2:
Seems like I don't get the standard AuthBearer way to work either (following the tutorial).
from django-ninja.
I don't know if there is a bug or not, but I could make it work with the ApiKey(APIKeyHeader) method in my production environment. I contaminated every second line of my script with loggers, and for the AuthBearer method, it seems like the authentication function is never called. Has anyone experienced a similar thing?
from django-ninja.
@fantasticle
nope, there is a chance you have some typo :)
without a code could not help
from django-ninja.
Hi, found this post to implement auth https://www.reddit.com/r/django/comments/r2tti8/django_ninja_auth_example/
But that did not work for me.
from django-ninja.
@bencleary's comment above worked for me. However, it's less than ideal and isn't something I want to go to production with since it installs the Django Rest Framework because it is a dependency of djangorestframework-simplejwt.
I'm curious, what didn't work in the example you linked to? I think the solution you linked to since it uses PyJWT.
P.S. your link didn't work when I clicked on it. I had to copy and paste it.
For the project I'm working on, I'm also considering going back to just using django_auth
and coming up with a system for the front-end to use csrf tokens.
from django-ninja.
I'm curious, what didn't work in the example you linked to?
I've got the working one based on that!
def create_token(username):
jwt_signing_key = getattr(settings, "JWT_SIGNING_KEY", None)
jwt_access_expire = getattr(settings, "JWT_ACCESS_EXPIRY", 60)
payload = {"username": username}
access_expire = datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(
minutes=jwt_access_expire
)
payload.update({"exp": access_expire})
token = jwt.encode(payload=payload, key=jwt_signing_key, algorithm="HS256")
return token
class AuthBearer(HttpBearer):
def authenticate(self, request, token):
jwt_signing_key = getattr(settings, "JWT_SIGNING_KEY", None)
try:
payload = jwt.decode(token, key=jwt_signing_key, algorithms=["HS256"])
except Exception as e:
return {"error": e}
username: str = payload.get("username", None)
return username
@api.post("/sign_in", auth=None)
def sign_in(request, username: str = Form(...), password: str = Form(...)):
user_model = get_object_or_404(User, username=username)
passwords_match = check_password(password, user_model.password)
if not passwords_match:
raise ValidationError([{"error": "Wrong password"}])
token = create_token(user_model.username)
return {"token": token}
from django-ninja.
@ognjenk
How I can unittest sign in endpoint?
def test_sign_in(self):
"""Test Sing in."""
data = {
"username": "TestUserName",
"password": "test"
}
response = self.client.post(
path="/api/sign_in",
data=data,
content_type="application/x-www-form-urlencoded",
follow=True
)
self.assertEqual(response.status_code, 200)
This code returns me AssertionError: 422 != 200
from django-ninja.
@ognjenk
Thank you. Although I've found one more easy solution:
...
username: str = Form(...), password: str = Form(...)
...
def test_sign_in(self):
"""Test Sing in."""
data = {"username": "TestUserName", "password": "test"}
response = self.client.post(
path="/api/sign_in",
data=data,
# or like this
# data=f"username=TestUserName&password=test",
# content_type="application/x-www-form-urlencoded",
)
self.assertEqual(response.status_code, 200)
I just had to remove this line content_type="application/x-www-form-urlencoded"
and it worked like I did a json request.
I wonder do you user roles (Django user groups) to split access to different endpoints?
from django-ninja.
No, we have rolled out our own solution for endpoint authorization.
We cache it in Redis per user and have created a custom decorator which we use for endpoints that need the check.
from django-ninja.
Is it secure to have a static "JWT_SIGNING_KEY" like that?
from django-ninja.
Related Issues (20)
- [BUG] Can't use parameter `keys`
- how to add a description for query params that shows in the generated docs?
- Field with list factory causes API docs to not load with non-serializable. HOT 2
- Annotate Decimal field does not supported "Unable to serialize unknown type: <class 'ellipsis'"
- Traversing the data structures to create an HTTP API client HOT 3
- how to use token ? HOT 1
- Path parameters, order matters HOT 3
- [BUG] Combining JWTAuth with django_auth only works in that order
- [BUG] Pydantic 2.7.0 incompatibily HOT 4
- [BUG] ModelSchema with ManyToManyField won't work under async views HOT 5
- How do you use aliases with nested objects
- [BUG] HOT 1
- [BUG] ModelSchema does not mark field as required if it has a default value
- [BUG] Swagger uses wrong endpoints for dynamically generated routers HOT 2
- Async reverse relationship HOT 4
- [BUG] Handler functions with same path but different http method can't use different path variable names
- [BUG] cdn error. HOT 3
- [BUG] paginate decorator with custom HTTP status `response={200: ..., 201: ...}` doesn't work HOT 3
- [BUG] Bearer authentication example from documentation doesn't work HOT 1
- `get_openapi_schema` outputs types using `anyOf` style - doesn't work with the Swift OpenAPI generator
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from django-ninja.