Created an API but getting 511 network authentication error at client end - rest

I am trying to create a simple web app, where I am using Go to create the backend and svelte to create the frontend. Backend is hosted on port 8080 and frontend on 5173. I used a node package 'localtunnel' to forward both the ports.
When I am sending a GET request on the forwarded backend port it is working fine but when I am using fetch(window.fetch) on the same from the svelte app it is giving 511 network authentication error. Please see the below codes:
Go Backend:
func enableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", "https://chilly-rabbits-film-146-196-44-202.loca.lt")
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I am providing the forwarded address of svelte app (PORT: 5173)
}
// Wrapper handler function
func handleRequest() {
handler := mux.NewRouter()
handler.HandleFunc("/sant", argHandler).Methods("GET")
log.Fatal(http.ListenAndServe(":8080", handler))
}
func argHandler(w http.ResponseWriter, r *http.Request) {
enableCors(&w)
w.Header().Set("content-type", "application/json")
.
.
.
var data Data
_ = json.Unmarshal(file, &data)
var sant string
sant = <some data is assigned>
json.NewEncoder(w).Encode(santa)
Svelte frontend:
<script>
let name;
async function fetchData() {
const endpoint = "https://giant-words-help-146-196-44-202.loca.lt/sant";
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ forwarded port of Backend API(PORT: 8080)
const response = await fetch(endpoint, {
"Content-Type": "application/json",
Accept: "application/json",
});
name = await response.json();
}
</script>
Getting the following error:
GEThttps://giant-words-help-146-196-44-202.loca.lt/sant [HTTP/2 511 Network Authentication Required 1560ms]
If I open https://giant-words-help-146-196-44-202.loca.lt/sant once on a new browser tab then the whole thing some how starts to work. But for Each network who is accessing the app need to open the link once to access the app.
Could you please help me figuring this out.
Thanks in advance! :)

Related

How to get refresh token after authenticate via pkce flutter app with keycloak using openid_client?

I have the following KeyCloak Client config, to use pkce authentication flow:
Realm: REALM
Client ID: pkce-client
Client Protocol: openid-connect
Access Type: public
Standard Flow Enabled: ON
Valid Redirect URIs: http://localhost:4200/
Advanced Settings:
Proof Key for Code Exchange Code Challenge Method: S256
When authenticating with flutter App with iOS Simulator via openid_client
https://pub.dev/packages/openid_client like this
authenticate() async {
var uri = Uri.parse('http://$localhost:8180/auth/realms/REALM');
var clientId = 'pkce-client';
var scopes = List<String>.of(['profile', 'openid']);
var port = 4200;
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
urlLauncher(String url) async {
if (await canLaunch(url)) {
await launch(url, forceWebView: true);
} else {
throw 'Could not launch $url';
}
}
var authenticator = new Authenticator(
client,
scopes: scopes,
port: port,
urlLancher: urlLauncher,
);
var auth = await authenticator.authorize();
var token= await auth.getTokenResponse();
return token;
}
I get the following response:
How do I get a new access token with the refresh token?
I tried:
POST http://localhost:8180/auth/realms/REALM/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
client_id: pkce-client
grant_type: refresh_token
refresh_token: "received refresh token"
but I get:
{"error":"invalid_client","error_description":"Invalid client credentials"}
How do I need to prepare the request to refresh the access token?
Thanks in advance
One cause of the problem could be that you need to include the client_secret as well in the request. This might be needed if the client is a "confidential" client.
Se the discussion here for further details. Refresh access_token via refresh_token in Keycloak

Cannot authenticate via pkce flutter app with keycloak using openid_client

I have the following KeyCloak Client config, to use pkce authentication flow:
Realm: REALM
Client ID: pkce-client
Client Protocol: openid-connect
Access Type: public
Standard Flow Enabled: ON
Valid Redirect URIs: http://localhost:4200/
Advanced Settings:
Proof Key for Code Exchange Code Challenge Method: S256
I try to authenticate in a flutter App with iOS Simulator via openid_client
https://pub.dev/packages/openid_client like this
authenticate() async {
var uri = Uri.parse('http://$localhost:8180/auth/realms/REALM');
var clientId = 'pkce-client';
var scopes = List<String>.of(['profile', 'openid']);
var port = 4200;
var redirectUri = Uri.parse(http://localhost:4200/);
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
urlLauncher(String url) async {
if (await canLaunch(url)) {
await launch(url, forceWebView: true);
} else {
throw 'Could not launch $url';
}
}
var authenticator = new Authenticator(
client,
scopes: scopes,
port: port,
urlLancher: urlLauncher,
redirectUri: redirectUri,
);
var auth = await authenticator.authorize();
var token= await auth.getTokenResponse();
return token;
}
But it only gives me this web view:
The Terminal where KeyCloak is running gives me the following lines:
INFO [org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker] (default task-34) PKCE enforced Client without code challenge method.
WARN [org.keycloak.events] (default task-34) type=LOGIN_ERROR, realmId=REALM, clientId=pkce-client, userId=null, ipAddress=127.0.0.1, error=invalid_request, response_type=code, redirect_uri=http://localhost:4200/, response_mode=query
When using Postman it worked and it provided me the Login page:
But I have additional parameters there, which I do not know where to add them in Authenticator(..) when using openid_client, state is automatically added.
state: <state>
code_challenge: <code-challenge>
code_challenge_method: S256
Do I need to add these code_challenge parameters somewhere in the openid_client method?
Or do I need to change the redirect URL when using an App? I tried with the package_name like proposed here (https://githubmemory.com/repo/appsup-dart/openid_client/issues/32), but it did not work either.
See the source code:
: flow = redirectUri == null
? Flow.authorizationCodeWithPKCE(client)
: Flow.authorizationCode(client)
You have specified redirectUri, so authorizationCode flow was used. But you want authorizationCodeWithPKCE flow in this case. So just make sure redirectUri is null and correct PKCE flow (with correct url parameters, e.g. code_challenge) will be used.
You need to send the redirectUri:null and set the port to 3000 ( you can use your port ).
after that you need to add the redirect uri in keycloak like this http://localhost:3000/ .it will do the trick
(what happening is when you send the redirect uri as null value, open_id client use the pkce flow and use the default url)

flutter web: how to connect to a rest API or localhost

My code:
void checkState() async {
print("CTC");
var url = "http://localhost:3000";
try {
var respX = await http.get(url);
} catch (err) {
print("response Arrived: $err");
}
}
But it is not possible:
https://github.com/flutter/flutter/issues/43015#issuecomment-543835637
I am using google chrome for debugging. simply pasting http://localhost:3000 allows me to connect to the URL from the same browser.
Is there any way to do it?
This issue was not with the flutter. It is the CORS policies in the browser as well as the server that blocked the request. I hosted it in a nodejs server with express. Here what I have did to solve this:
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
You can change the 'Access-Control-Allow-Origin' to the domain you are calling from if you want to. Else it will allow request from everywhere.
Remember, the localhost of your emulator is not the localhost of your machine. To test the API running on your machine you have to point to the ip adress of your computer

Axios sending OPTIONS instead GET

I'm trying to make api calls locally in a react app using axios.
I've already added django-cors-headers and followed the documentation, but it does not seem to be working.
I always get the error:
localhost/:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/todos/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
my base.py:
INSTALLED_APPS = [
# ...
"corsheaders",
"rest_framework",
"todo",
"api",
]
MIDDLEWARE = [
# ...
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
# ...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = False
In my react app:
const [todos, setTodos] = useState({})
useEffect(
() => {
axios.get(
api_url, {
headers: {
"Access-Control-Allow-Origin": "*",
}
}
).then(
res => {
setTodos(res.data);
console.log(res.data)
}
).catch(
err => {
console.log(err)
}
)
}, []
)
Note, even without configuring a whitelist and reverting the CORS settings to:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
I still manage to get the data in a get call using httpie, just running http + url.
Note 2: When the axios tries to get the data, I get this on the terminal running the Django app:
[04/Jun/2019 18:15:29] "OPTIONS /api/todos/ HTTP/1.1" 200 0
IMPORTANT EDIT:
The problem does not seem to be with my server, I used fetch instead of Axios and everything occurred normally. With Axios, my server was getting an OPTIONS method, and, I do not know why, I was giving this problem with CORS.

angular 2 login with spring security

im trying to integrate spring security with a custom angular 2 login, that is a specific endpoint of my app is protected with spring security, trying to access it will redirect to /login that is handled in angular 2. as things stands now i have no clue as to how to perform the login and grant access to the backend API once logged.
i am configuring spring security as follows:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().and()
.authorizeRequests()
.antMatchers("/api/someEndpoint/**")
.hasRole(ADMIN_ROLE).and().formLogin()
.loginPage("/login").and().logout();
}
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
as I had the default login everything worked fine, but I have found myself unable to create a working angular 2 login integration.
I tried the following code in angular 2 to no avail:
login(loginDetails:Object) {
console.log(loginDetails)
const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers: headers });
const body = JSON.stringify(loginDetails);
console.log(headers);
console.log(body);
return this.http.post(this.loginUrl, body, options)
}
as far as I know spring security defaults for username and password variable names are "username" and "password", which i am sure are being passed in the request body so when passing some invalid user data like {"username":"admin", "password" : "pass"}I should be redirected to /login?error or something, and when successfully authenticated I should be redirected to /welcome and stay authenticated
I have the user and pass defined in my db and my custom userDetailsService checks against it
any answers, comments or questions are welcome
Once you're working with an API you've to use the HTTP Basic authentication.
It's also required to use HTTPS to prevent the main-in-middle attack.
To implement HTTP Basic with Angular the login service would look like this:
login (loginDetails: any): Observable<LoginResponse> { // custom class, may be empty for now
let headers = new Headers({
'Authorization': 'Basic ' + btoa(loginDetails.login + ':' + loginDetails.pass),
'X-Requested-With': 'XMLHttpRequest' // to suppress 401 browser popup
});
let options = new RequestOptions({
headers: headers
});
return this.http.post(this.loginUrl, {}, options)
.catch(e => this.handleError(e)); // handle 401 error - bad credentials
}
... then you subscribe this in the caller component:
loginNow() {
this
.loginService
.login(this.loginDetails)
.subscribe(next => {
this.router.navigateByUrl("/"); // login succeed
}, error => {
this.error = "Bad credentials"; // or extract smth from <error> object
});
}
Then you can use the loginNow() method inside component templates like (click)="loginNow().
As soon as the server will accept an authorization, JSESSIONID will be stored in your browser automatically because of Spring Security features and you won't be forced to send the credentials each time you access private resources.
Your login server method may look like this:
#PreAuthorize("hasRole('USER')")
#PostMapping("/login")
public ResponseEntity login() {
return new ResponseEntity<>(HttpStatus.OK);
}
... it would reject with 401 UNAUTHORIZED when the authorization fails or accept with 200 SUCCESS when it's not.
How to setup a server in the proper way there's a number of Spring Security demo projects present: https://github.com/spring-guides/tut-spring-security-and-angular-js
Your spring security config needs to look like this
http!!
.cors().and()
.csrf().disable()
.authorizeRequests()
.requestMatchers(object: RequestMatcher {
override fun matches(request: HttpServletRequest?): Boolean {
return CorsUtils.isCorsRequest(request)
}
}).permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().permitAll()
I had a similar issue, but I had to override the successlogout handler as mentioned here.