I've problem with setting token with react app. Im getting "refresh-token" from API response
private void SetTokenCookie(string token)
{
var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions
{
HttpOnly = true,
Expires = DateTime.UtcNow.AddHours(8),
Path = "/auth/refresh-token"
};
Response.Cookies.Append("refreshToken", token, cookieOptions);
}
There is no problem in Postman. I received from response in Headers -> Set-Cookie - refreshToken=3CTqZ6GQNT%2FxsmbUjFJQnkdkSd1utwtPtmxBtpawbZXCXwLR1HqvM3u3ZeJ6rRoidOSUTDJ17B0tku2PD7qeVw%3D%3D; expires=Tue, 14 Dec 2021 23:57:32 GMT; path=/auth/refresh-token; secure
But when im using browser, this cookie is not saving.
Related
I'm trying to update the User in Django from react side.
The same function has worked on testing through Postman. But when I try to make a request using Axios in react.js Django doesn't accept it. and throw 401 error.
[23/Feb/2022 02:32:11] "PUT /api/v1/accounts/user-profile-update/ HTTP/1.1" 401 58
On the postman, I'm using Bearer Token for authorization. And the same token I'm passing in headers config.
// Related Action Code
const userData = JSON.parse(localStorage.getItem('userData'))
const config = {
headers: {
'Content-type': 'application/json',
Authorization: `Bearer ${userData.token}`
}
const { data } = await axios.put(
`/api/v1/accounts/user-profile-update/`,
config
)
EDIT :
Related API VIEW:
#api_view(['PUT'])
#permission_classes([IsAuthenticated])
def updateUserProfile(request):
data = request.data
user = request.user
serializer = UserSerializerWithToken(user, many=False)
user.name = data['name']
user.phoneNumber = data['phoneNumber']
user.city = data['city']
user.postalCode = data['postalCode']
user.country = data['country']
user.save()
return Response(serializer.data)
Two different responses on Django server:
With Postman
[23/Feb/2022 02:14:16] "PUT /api/v1/accounts/user-profile-update/%0A HTTP/1.1" 200 1182
And with React frontend
[23/Feb/2022 02:32:11] "PUT /api/v1/accounts/user-profile-update/ HTTP/1.1" 401 58
Can anybody find out why this happening? And how to fix that problem.
EDIT: Note: This problem only happens on PUT or PATCH requests and work with GET requests.
I'm still unable to figure out why this is happening. If I use the
same token and test my views with Postman they work absolutely fine
but not with a react-redux setup.
We are trying to configure swagger in our .NET 6 API project so that it automatically retrieves the access_token from Azure token endpoint with "client credentials flow". Here is the configuration part in startup.cs
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "register_api", Version = "v1" });
c.SchemaFilter<EnumSchemaFilter>();
var jwtSecurityScheme = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Scheme = "bearer",
BearerFormat = "JWT",
Flows = new OpenApiOAuthFlows
{
ClientCredentials = new OpenApiOAuthFlow
{
TokenUrl = new Uri(#"https://login.microsoftonline.com/512024a4-8685-4f03-8086-14a61730e818/oauth2/v2.0/token"),
Scopes = new Dictionary<string, string>() { { #"api://e92b626c-f5e7-422b-a8b2-fd073b68b4a1/.default", ".default" } }
}
}
};
c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, jwtSecurityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ jwtSecurityScheme, new string[] { #"api://e92b626c-f5e7-422b-a8b2-fd073b68b4a1/.default" } }
});
}
It looks as follows when the user clicks the "Authorize" button the first time. But then, after entering the client_id and client_secret and clicking Authorize button, it shows up the message "Auth Error TypeError: Failed to fetch"
There is something weird with the request that is sent to the token endpoint. The payload includes just the grant_type and the scope. But the client_id and client_secret are base64 encoded and sent in Authorization header:
Is it the reason that the Azure token endpoint refuses to generate the access_token? I have used the same token endpoint and succeeded to get token with postman, but I included all the parameters in the payload.
If that is the case, is it possible to change the configuration of Swagger so that client_id and client_secret are sent in the payload instead (together with the grant_type and the scope) ?
I have the following problem. I am trying to set httpOnly cookie and nothing happens. I spent a few hours trying to solve this issue and I have no idea what is going on... My architecture is the following:
Backend: Python fast-api hosted on Heroku, available at https://api.mysuperdomain.com.
Frontend: GatsbyJs hosted on Netlify, available at https://mysuperdomain.com
When I call login request from React component:
const handleSubmit = async (e) => {
e.preventDefault()
const config = {
headers: {
crossDomain: true,
withCredentials: true,
'Content-Type': 'application/x-www-form-urlencoded'
}
}
const requestBody = {
username: emailRef.current.value,
password: passwordRef.current.value
}
try {
const data = await axios.post('https://api.mysuperdomain.com/login', qs.stringify(requestBody), config)
I get response from my backend with headers, set-cookie:
set-cookie: Authorization="Bearer somethinghere"; Domain=.mysuperdomain.com; expires=Tue, 28 Jul 2020 20:40:32 GMT; Max-Age=1800; Path=/; SameSite=lax
unfortunately in browser storage I cannot see this cookie.
My backend(API) sets the cookie in the following way:
#app.post("/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect username or password")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": form_data.username}, expires_delta=access_token_expires
)
token = jsonable_encoder(access_token)
response = JSONResponse({'status': 'authenticated'})
response.set_cookie(
key="Authorization",
value=f"Bearer {token}",
domain=".mysuperdomain.com",
httponly=True,
max_age=1800,
expires=1800,
)
return response
My DNS records are within the Cloudflare, and CNAME record for backend is proxied:
Typ Name Content TTL Proxy status
CNAME api limitless-starfish-something.herokudns.com Auto Proxied
SSL/TLS encryption mode is Flexible (Encrypts traffic between the browser and Cloudflare). Backend at Heroku has no SSL Certificate therefore I set flexible SSL/TLS encryption mode.
Maybe it is somehow related to above config?
I think this happens because you didn't add a CORS middleware to your app, in FastAPI, allow_credentials is set to bool = False in default. But you can change that easily.
First you need to import CORSMiddleware from fastapi.middlewares
from fastapi.middleware.cors import CORSMiddleware
Then we can add a middleware to our app
app.add_middleware(
CORSMiddleware,
allow_credentials=True,
)
Also you can add origins and all other stuff with CORSMiddleware, for more related info check FastAPI-CORS out.
I am using identityserver4 to secure my apis.
When the token expires, in addition to sending error message 401, how can I send a json object in the body with the error description? I am using .net core.
There is actually a spec for how to do this:
https://www.rfc-editor.org/rfc/rfc6750#section-3
You can provide additional info in the WWW-Authenticate response header.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",error="invalid_token",error_description="The access token expired"
It should be possible to replace this header if token validation fails via the middleware JwtBearerEvents object.
As other response mentioned this is possible by setting WWW-Authenticate header in Unauthorized response. Here is code on API's startup.cs to make this happen:
services.AddAuthentication("Bearer").AddJwtBearer("Bearer",
options =>
{
options.Authority = "http://localhost:5000";
options.Audience = "api1";
options.RequireHttpsMetadata = false;
options.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = OnAuthenticationFailed
};
});
}
private Task OnAuthenticationFailed(AuthenticationFailedContext context)
{
if (context.Exception is SecurityTokenExpiredException expiredException)
{
context.Response.Headers.TryAdd(HeaderNames.WWWAuthenticate,
new StringValues(new[] {
JwtBearerDefaults.AuthenticationScheme,
"error=\"invalid_token\"",
"error_description=\"The access token expired\""
}));
}
return Task.CompletedTask;
}
The JWT handler is from Microsoft and IdentityServer using it internally.
Application Setup
Client - AngularJS (hosted at client.domain.com)
API + SignalR - Hosted at api.domain.com
SignalR setup class
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
And I do following from Authentication service
AuthenticationManager.SignOut();
List<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, myuserid));
ClaimsIdentity id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.Current.GetOwinContext().Authentication.SignIn(new AuthenticationProperties() { IsPersistent = false }, id);
Authentication response looks like
HTTP/1.1 200 OK
Cache-Control: private
Pragma: no-cache
Content-Length: 556
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: *
Set-Cookie: ASP.NET_SessionId=pvasgf4q2klfbmk4oojqkxm5; path=/; HttpOnly
X-AspNet-Version: 4.0.30319
Set-Cookie: .AspNet.ApplicationCookie=1lBbz_FRNvxt1AhwkzZHFoiyhyZgsasNXStV3SbjQUHt0hqxTG--yXtjYNquB4zmQn-6M99pqHRPHaT4uf8g1JAnqg5WldD65IJ_FxYoEucf_WvV1fY4pwf774Cyo6fhI5nVk9Z6fdpjY422eo0GIibIMhaV9QvHNaiSsbFO0koT-CnhQuD5DED_418nP7m4FBbXdwIbFM_squ0bVYKXuB35jm57zVk9hUVWdlPmWxc; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Tue, 30 Dec 2014 00:20:29 GMT
When I the app makes request to signalr/negotiate, it receives 401 (unauthorized) because the cookie received in authentication response is not being sent with signalr request.
Is there anything I am missing?
UPDATE 1
All of above works fine when client and api are hosted in the same domain like this.
Client - www.domain.com/client
API - www.domain.com/api
UPDATE 2
Upon digging a little further, I realized that the issue is not related to signalr at all. I wrote a light client just to see if I can authenticate and follow that up with a simple get request. I hosted the client at api.domain.com/lightclient and made api requests to api.domain.com/api everything works. The following get request has the authentication cookie. However, when I moved the client to client.domain.com, browser removes the cookie.