I am trying to implement Authorization with Axios on RN part and send the token to Spring Boot backend. I've tried to do it before with simple sending email and password as parameters of GET request and it worked fine, but now when I'am trying to send basic headers with btoa to backend part, it keeps receiving null value.
My React Native part:
login(user) {
const headers = {
authorization: 'Basic ' + btoa(user.email + ':' + user.password)
};
return axios.get(API_URL + 'login', {headers: headers})
.then(response => {
console.log('function called')
And my Controller on Spring Boot:
#RequestMapping(value = {"/login"}, method = RequestMethod.GET)
public ResponseEntity<?> login(Principal principal) {
if(principal == null){
//logout will also use here so we should return ok http status.
return (ResponseEntity<?>) ResponseEntity.badRequest();
}
UsernamePasswordAuthenticationToken authenticationToken =
(UsernamePasswordAuthenticationToken) principal;
When I debug the controller, I see that my method parameter principle is receiving null.
I guess the issue might be somewhere either in the header or Controller parameter, but have real idea.
Headers should be:
{
headers: {
"Authorization": "Basic "...
}
}
Alternatively,
{
auth: {
username: "",
password: ""
}
}
Which will add the basic auth header for you
https://github.com/axios/axios#request-config for reference
Related
I have a project divided in two layers. The back-end is developed in spring boot, secured by Sprint security and JWT, and the front-end is developed in Vue.js, using Axios library for communication between layers.
I receive the "Bearer token" authentication properly, and all the authentication process is done correctly. The issue appears when I try to send a request with a token header to access content but the token doesn't send, and the Spring boot returns null without the content.
Here is the code
getOffers: function () {
if (localStorage.getItem("userSession")) {
this.aux = JSON.parse(localStorage.getItem("userSession"));
this.token = this.aux.token;
this.tokenHeader = "Bearer "+this.token;
alert(this.tokenHeader)
};
console.log(`Bearer ${this.token}`)
axios.
get('http://localhost:8080/api/v1/offer', {'Authorization' : `Bearer ${this.token}`})
.then(response => {
console.log(response);
this.offers = response.data
}).catch(e => console.log(e))
}
P.S: When I make a request in Postman, it works fine and returns the desired object. Here is a postman example:
postman
Correct way to pass header is :
axios.get(uri, { headers: { "header1": "value1", "header2": "value2" } })
In your case try this:
axios.get('http://localhost:8080/api/v1/offer', { headers:{Authorization : `Bearer ${this.token}`} })
Also, check in console if this gives correct Bearer token:
console.log(`Bearer ${this.token}`)
Register the Bearer Token as a common header with Axios so that all outgoing HTTP requests automatically have it attached.
window.axios = require('axios')
let bearer = window.localStorage['auth_token']
if (bearer) {`enter code here`
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + bearer
}
And no need to send bearer token on every request.
I'm making an axios post call with the JWT token generated after successful login. For all the requests I need to attach JWT token in header and in the back-end which is developed on spring -boot I have logic to get the token from header and validate it.
From the browser, first the OPTIONS request goes to back-end where it gives me 403 error and in the back-end If I sysout headers, I can't find the header name X-XSRF-TOKEN
axios.post("http://localhost:8004/api/v1/auth", { "username": "test", "password" : "test"})
.then((response) => {
let token = response.data.token;
axios.defaults.headers.common["X-XSRF-TOKEN"] = token;
axios.post("http://localhost:8004/api/v1/getdata", {"action" : "dashboard"})
.then((response) => {
console.log(response.data);
}, (error) => {
console.log(error);
})
}, (error) => {
console.log(error);
})
Spring boot part
#Controller
#CrossOrigin(origins = "*", allowedHeaders = "*")
#RequestMapping(path = "/api/v1")
public class ApplicationController {
#PostMapping(path = "/getdata")
#ResponseBody
public SessionData getData(#RequestBody ProfileRequest profileRequest) {
try {
return profileService.getData(profileRequest);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Setting Authorization Header is not something to do with vue, but it
is something to do with axios.
axios.post("http://localhost:8004/api/v1/getdata", {"action" : "dashboard"}, {
headers: {
Authorization: 'Bearer ' + token,
}
})
When you get the auth token you can configure the axios instance with:
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`
common means applying the header to every subsequent request, while you can also use other HTTP verb names if you want to apply a header to only one request type:
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
You will find more info in https://github.com/axios/axios#config-defaults
...
axios.post('http://localhost:8004/api/v1/auth',
{ "username": "test", "password" : "test"}, {headers: { X-XSRF-TOKEN: `${token}`}})
...
the issue might not be axios but the cors policy set by spring security.
If you are using spring security check out this answer
I had the same issue, that answer helped solve my problem.
I am working on a springboot + angular project. And I am implementing oauth for the same.
My Spring boot Oauth services(oauth/token) works fine as expected and was tested in postman successfully. But as am trying to integrate that url with angular, i am continuously facing some trouble. I am always getting 401 unauthorized.
My Angular code is as below
login(userName:any,password:any){
console.log("logged in");
let params = new URLSearchParams();
params.set('username','1522856566577');
params.set('password','sens!tiveP#ss');
params.set('grant_type','password');
params.set('client_id','clientIdPassword');
params.set('client_secret','secret');
params.set('scope','read');
let headers = new HttpHeaders().
append('Content-type','application/x-www form-urlencoded;
charset=utf- 8').
append('Authorization','Basic '
+btoa("clientIdPassword:secret"));
let options = {
headers:headers
};
this.http.post('/api/oauth/token',params.toString(), options).subscribe(data => console.log(data),err => console.log('Invalid Credentials')); }}
When you are sending headers from angular, Api needs to allow origins of requests. Add this code in Spring Boot controller above the class like below. After that Api will be allowed to get headers.
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
public class AuthenticationController {
//services...
}
You are setting client id and secret twice in headers and url search params.try the following code to generate tokens in the service
getToken()
{
const httpOptions = {
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + btoa('your_client_id:your_client_pass')
})
};
var body = "grant_type=client_credentials";
return this.http.post('your_url',body,
httpOptions)
.pipe(map(res=>res.json()));
}
I am trying to refresh the access token for a user following this tutorial.
However, I am getting
{
"error":"unauthorized",
"error_description":"Full authentication is required to access this resource"
}
and I do not see what's missing.
The following is how I am constructing the oauth/refresh request in my Angular application:
refreshToken() {
this.logger.info('Attempting to refresh access token');
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')
// CLIENT_ID:CLIENT_SECRET
.set('Authorization', 'Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=');
const payload = {
refresh_token: AuthenticationService.getRefreshToken(),
grant_type: 'refresh_token'
};
return this.http.post(environment.apiUrl + '/oauth/refresh',
payload, {headers: headers})
.pipe(map(r => r));
}
What am I missing here?
Okay, I was almost right.
First, I did use the wrong endpoint /oauth/refresh - I don't know why I thought this existed. It has to be /oauth/token.
Also payload gets send via URL parameters:
const payload = `refresh_token=${AuthenticationService.getRefreshToken()}&grant_type=refresh_token`;
So in the end I got this working with:
refreshToken() {
this.logger.info('Attempting to refresh access token');
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')
.set('Authorization', 'Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=');
const payload = `refresh_token=${AuthenticationService.getRefreshToken()}&grant_type=refresh_token`;
return this.http.post(environment.apiUrl + '/oauth/token',
payload, {headers: headers})
.pipe(map(r => r));
}
I've seen a few answers on stackoverflow and I'm lost.
I have webapi 2 + standalone angular 2
webapi project is from template. the only thing i've changed is that i added CORS
and following line to IdentityConfig.cs > ApplicationUserManager Create()
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:3000" });
here I've all standard from template:
[Authorize]
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
On the client side I have function to get access token, that works properly:
authenticate(loginInfo: Login): boolean {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
this.http.post(this.baseUrl + 'Token', 'grant_type=password&username=alice2#example.com&password=Password2!',
{
headers: headers
})
.subscribe(
data => this.saveAuthToken(<AccessToken>(data.json())),
err => this.handleError(err),
() => console.log('authentication Complete')
);
return true;
}
And get function, that works ok without authentication (commented code) :
get(url: string) {
var jwt = sessionStorage.getItem(this.idTokenName);
var authHeader = new Headers();
if (jwt) {
authHeader.append('Authorization', 'Bearer ' + jwt);
}
return this.http.get(this.apiUrl + url, {
headers: authHeader
})
.map(res => res.json())
.catch(this.handleError);
//return this.http.get(this.apiUrl + url)
// .map(res => res.json())
// .catch(this.handleError);
}
But when i try to add Authorization header server returns:
XMLHttpRequest cannot load http://localhost:3868/api/values. Response for preflight has invalid HTTP status code 405
How to allow user to authenticate through Angular properly?
Install-Package Microsoft.Owin.Cors
Add to App_Start > Startup.Auth.cs > ConfigureAuth(IAppBuilder app)
app.UseCors(CorsOptions.AllowAll);
Only one line. That's all.
You could explicitly add the needed headers and methods:
context.Response.Headers.Add(
"Access-Control-Allow-Headers",
new[] { "Content-Type, Authorization" }
);
context.Response.Headers.Add(
"Access-Control-Allow-Methods",
new[] { "GET, POST, OPTIONS" }
);
I had to add the following to the globalasax.cs:
protected void Application_BeginRequest()
{
var req = HttpContext.Current.Request;
var res = HttpContext.Current.Response;
var val = res.Headers.GetValues("Access-Control-Allow-Origin");
if (val == null)
{
if (!req.Url.ToString().ToLower().Contains("token") || (req.Url.ToString().ToLower().Contains("token") && req.HttpMethod == "OPTIONS"))
{
res.AppendHeader("Access-Control-Allow-Origin", "http://localhost:4200");
}
}
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
res.AppendHeader("Access-Control-Allow-Credentials", "true");
res.AppendHeader("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
res.AppendHeader("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
res.StatusCode = 200;
res.End();
}
}
When talking to webapi angular and using a http post that either contains non-standard body contents (i.e json) or authentication then a pre-flight request is set that basically says 'am i okay to send the actual request'. Now there are several ways around this that essentially involve short cuts - use IE (if the server is on the same machine as IE ignores the port when deciding what the same machine is) or open CORS up to permit all (which is dangerous as the granting permission to an authenticated user opens your system up to all manner of hacks).
Anyway the solution we used was to add a method to the Globals.asax.cs on the server
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
var origin = HttpContext.Current.Request.Headers["Origin"];
Response.Headers.Add("Access-Control-Allow-Origin", origin);
Response.Headers.Add("Access-Control-Allow-Headers", "content-type, withcredentials, Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
Response.Headers.Add("Access-Control-Allow-Credentials", "true");
Response.Headers.Add("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT, DELETE");
Response.Flush();
}
}
Now the above is checking for the pre-flight very specifically and if it finds it it adds permissions to send the next request. On your system you may need to tweek the Allow_Headers request (easiest way is to use your browser f12 to look at what headers your pre-flight request is actually sending out.
Note that the above just deals with the pre-flight CORS will still apply for the actual http POST which will need correctly handling. For this we added the server we wanted to allow in to settings and then added the System.Web.Http.Cors to the WebApiConfig Register method as follows
var cors = new EnableCorsAttribute(Properties.Settings.Default.CORSOriginPermittedSite, "*", "GET, HEAD, OPTIONS, POST, PUT, DELETE");
cors.SupportsCredentials = true;
config.EnableCors(cors);
This avoids hard coding the site which a production system really wants to avoid.
Anyway hopefully that will help.