Keycloak logout endpoint not deleting session - session

Hello fellow programmes,
I am stuck on the issue with keycloak. I am trying to send from node.js express framework request towards keycloak to logout the user.
Config.keycloakClient = my_realm
Config.keycloakURL = keycloak URL
request.get({
//url: join(Config.keycloakURL, '/auth/realms/'+ Config.keycloakClient+ '/protocol/openid-connect/logout?' + 'id_token_hint='+req.headers.oidc_access_token), <--- tried this
url: join(Config.keycloakURL, '/auth/realms/'+ Config.keycloakClient+ '/protocol/openid-connect/logout'), // <-- i also tried this
headers:
{ Authorization: "Bearer " + req.headers.oidc_access_token, // <-- also tried Authorization: req.headers.oidc_access_token }
Result - 200 OK, but i can still see active session in active sessions in admin interface
request.post({
//url: join(Config.keycloakURL, '/auth/realms/'+ Config.keycloakClient+ '/protocol/openid-connect/logout?' + 'id_token_hint='+req.headers.oidc_access_token), <--- tried this
url: join(Config.keycloakURL, '/auth/realms/'+ Config.keycloakClient+ '/protocol/openid-connect/logout'), // <-- i also tried this
headers:
{ Authorization: "Bearer " + req.headers.oidc_access_token, // <-- also tried Authorization: req.headers.oidc_access_token }
Result - 302 redirect, but i can still see active session in active sessions in admin interface
I was trying to find the refresh token, but when accessing
Config.keycloakURL/auth/realms/{realm}
i could not get the refesh token-> it redirects me to the login page.
In session storage / cookies i can not see anything strange via chrome dev tools.
So what is the proper way to logout with endpoint? Which endpoint and what parameters should i use please? And how am i to obtain refresh token?
Thanks for the help!
Best regards

Related

Ruby rest-client 401 Unauthorized after post of data

I'm new to using the rest-client. I know I'm missing something, but I am trying to do the following:
Post to a login endpoint to authenticate
After authentication, post csv text to another endpoint that requires a logged in user
The authentication portion is successful, however, I am getting a 401 Unauthorized when step 2 occurs.
rest_client = RestClient
login_response = #global_rest_client.post(
host + 'LOGIN ENDPOINT',
{ userName: 'user', password: 'password'},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
)
import_response = rest_client.post(
host + 'IMPORT DATA ENDPOINT',
headers: { 'X-System-Name': 'AndroidMobile', 'Content-Type': 'multipart/form-data },
csv: csv_string
)
My understanding of how authentication works could be wrong. My assumption is that as long as the same instance of the client has a successful login, then the post of csv data would also be successful.
I appreciate any input.
HTTP (1.1) is stateless so a request does not contain any information about previous requests unless that information is encoded and added to the request in some way (e.g. cookies or headers). So when you make your import request the server does not know if/that you are authenticated even though you just made a login request.
You'll have to include the token you receive from your login request in subsequent requests. This should go in the 'Authorization' header.
For example:
auth_token = login_response["success"]["token"] # or whatever the key is for the token
import_response = rest_client.post(
host + 'IMPORT DATA ENDPOINT',
headers: { 'Authorization': "Bearer #{auth_token}", 'X-System-Name': 'AndroidMobile', 'Content-Type': 'multipart/form-data },
csv: csv_string
)
The way authentication works depends on the server and can be different in different cases. So the site you are accessing might expect the Authorization header to be like "Token #{auth_token}" or anything else, but they should mention it in their documentation.

CORs error when accessing Square V2 API

I'm making a client-side request out to V2 of the Square API using Vue and Axios. My Vue component is as follows:
import axios from 'axios';
export default {
mounted() {
var instance = axios.create({
baseURL: 'https://connect.squareup.com/v2/',
timeout: 1000,
headers: {
'Authorization': 'Bearer xxxxxxxxxxxxxxxxx',
'Accepts': 'application/json',
'Content-Type': 'application/json'
}
});
instance.get('catalog/list')
.then(function (response) {
console.log(response);
}) ;
}
}
However, when I make that call, I receive the following error:
Failed to load https://connect.squareup.com/v2/catalog/list: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://local-env.dev' is therefore not allowed access. The response had HTTP status code 403.
That error suggests that there is some configuration that has to happen on the Square side, but I saw no opportunity to whitelist domains, etc.
Has anyone come across this error before, regardless of service, and if so, how did you resolve?
I don't think the Square API supports being called from a browser. I used Postman to do an OPTIONS request on https://connect.squareup.com/v2/catalog/list and the response was a NOT_FOUND. The OPTIONS request is needed for proper CORS support.
Plus, if you did this, I would think your auth token would need to be sent to the client -- thus exposing it to everyone. It looks like the Square API is only designed to be called from a server. But that is just based on me skimming the docs a bit. I have no experience using their API.
When doing OAuth authorization request you are not supposed to do it from your application. Create and URL with the parameters and open it in a new browser window or tab, Something like:
const grants='MERCHANT_PROFILE_READ CUSTOMERS_READ CUSTOMERS_WRITE PAYMENTS_READ PAYMENTS_WRITE PAYMENTS_WRITE_ADDITIONAL_RECIPIENTS PAYMENTS_WRITE_IN_PERSON';
const params = new HttpParams()
.set('scope', grants)
.set('client_id', <YourSquareApplicationId>)
.set('state', '1878789');
const requestUrl = `${<squareUrl>}/oauth2/authorize?${params.toString()}`;
window.open(requestUrl, "_blank");
That new window is supposed to ask the end user to login to his account and accept or deny the request.

Can Ajax make a Cross-Origin Login?

I'm trying to login from one of my servers to another in order to send cross-origin requests that requires being logged. is it possible?
I have two web servers, A and B. Lets say www.a.com and www.b.com.
B has an API that can be used only if the client is logged in. I need to use that API from A clients.
So, I send from A client an ajax (post) login request to B. B responses with CORS headers, the session cookie and a successful redirection to B's home/index.
But when I make a second ajax request (jsonp request) from A client to B server, this request doesn't send the previous session cookie received, therefore the login request failed.
If I login to www.b.com manually (in a second browser tab), all requests from A to B are successful detected as a logged user, so, the B API works from A.
I think that the session cookie received from my login requests is not being saved to the browser.
This is my login request:
$.post("www.b.com/login", { 'j_username': 'username', 'j_password': 'password' } );
Using:
jqXHR.withCredentials = true;
settings.crossDomain = true;
Response headers:
Access-Control-Allow-Headers:x-requested-with
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:*
...
Location:http://www.b.com/home
...
Set-Cookie:JSESSIONID=tY++VWlMSxTTUkjvyaRelZ0o; Path=/
The cookie received is being saved to www.a.com or to www.b.com? How can I set this cookie to www.b.com from an A client ajax request? I think that is the problem.
As apsillers said, we can't use the wildcard Access-Control-Allow-Origin:*.
But this doesn't solved the problem.
I was setting jqXHR.withCredentials = true; inside a beforeSend handler function.
$.post({
...
beforeSend: function(xhr) {
xhr.withCredentials = true;
},
...
});
And for some reason, this doesn't work. I had to set the use of credentials directly:
$.post({
...
xhrFields: {
withCredentials: true
},
...
});
This code works perfectly !
Thanks you.

Okta Authentication works but Get User by Id gives Invalid Token Provided

I have a Django app that authenticates using Okta:
headers = {
'Authorization': 'SSWS {}'.format(<okta api token>),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
authentication_payload = {
'username': <username>,
'password': <password>
}
response = requests.post(
<okta auth endpoint>,
headers=headers,
data=json.dumps(authentication_payload)
)
This works successfully. From the response content I am able to get the User Id:
content = json.loads(r.content.decode('utf-8'))
okta_user_id = content['_embedded']['user']['id']
I then use the okta_user_id to create the endpoint to get the okta user by id:
okta_user_endpoint = https://<org>.okta.com/api/v1/users/<okta_user_id>
I then use the same headers from the authentication call, with the same api token, and try to get the user by id:
user_response = requests.get(
okta_user_endpoint,
headers=headers
)
But this is unsuccessful. I get a 401 error with the following content:
{
"errorCode":"E0000011",
"errorSummary":"Invalid token provided",
"errorLink":"E0000011",
"errorCauses":[]
}
Seems straight forward with an invalid token, but if the token is invalid how am I able to successfully make the authentication call? And if the token if valid for the authentication call why is it not working to get the user by id?
Okta recently changed the way that the /authn endpoint works. The /authn endpoint no longer requires an authentication token. This was done in order to support single-page applications.
It looks like your application will need to be able to fetch user information on an arbitrary user. In that case, using an Okta API token makes sense.
However, if you were making that call from a single-page application, you would want to make a request to the /users/me API endpoint.

Google OAuth: can't get refresh token with authorization code

I am using Google API Client for Google Analytics with OAuth 2.0
I read this to get the refresh token but it doesn't appears: https://developers.google.com/identity/protocols/OAuth2WebServer#offline
I only get this instead:
{
"access_token": "ya29.twHFi4LsiF-AITwzCpupMmie-fljyTIzD9lG8y_OYUdEGKSDL7vD8LPKIqdzRwvoQAWd",
"token_type": "Bearer",
"expires_in": 3599,
"id_token": "very long string"
}
Here is the code:
Javascript (to get the Authorization Code): that works
gapi.analytics.ready(function() {
gapi.analytics.auth.authorize({
container: 'embed-api-auth-container',
clientid: '257497260674-ji56vq885ohe9cdr1j6u0bcpr6hu7rde.apps.googleusercontent.com',
});
gapi.analytics.auth.on('success', function(response) {
var code = response.code;
$.ajax({
url: "getTokensFromCode.php",
method: "GET",
data: {
"code": code
},
success: function (tokens) {
// I can't get refresh token here, only get "access_token" and "id_token"
console.log(tokens);
}
});
});
});
PHP (to exchange Authorization Code for tokens): that doesn't work
// I get the authorization code in Javascript
$code = $_GET['code'];
$redirectURI = "postmessage";
$client = new Google_Client();
$client->setClientId($clientID);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($redirectURI);
$client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->authenticate($code);
$tokens = $client->getAccessToken();
echo $tokens;
I need the refresh token in Javascript, that's why I get the authorization code in Javascript and make an Ajax request to get the refresh token.
You will only get the refresh_token the very first time that a user grants access to your app. You'll need to store the refresh_token somewhere to be able to use it afterwards. You won't get a new refresh token the next time a user logs in to your app.
FWIW: using a refresh token in a Javascript client doesn't make a lot of sense since a Javascript client can't store it in a safe (confidential) way. Since Javascript clients live in browsers and users are present in browsers, you can just redirect the browser to the authorization endpoint again and you'll get a new access token (which is also the purpose of a refresh token). The SSO session for the user at Google will make sure that the user doesn't need to login again and that the experience is seamless.
Check out this response by #curious_coder
Google API Refresh Token
He explains a way to get the Refresh Token every time :) Life saver. This post helped me get there so I figured I'd share this for any one else trying to find their refresh token. Add the last two lines of this code to your Auth process
$client = new Google_Client();
$client->setAuthConfigFile(__DIR__ . '/client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/dashboard/oauthcallbacks');
$client->addScope(Google_Service_Analytics::ANALYTICS_READONLY);
$client->setAccessType('offline'); //To fetch refresh token(Refresh token issued only first time)
$client->setApprovalPrompt('force'); //Adding this will force for refresh token
Also I used var_dump($tokens) to get the contents instead of echo. Dont remember if it makes a difference in PHP but $tokens will be an array of objects.

Resources