Hey @eelliston ,
So basically, we need to distinguish two things here:
- Token
- Session
Your token cannot be invalidated by doing Logout and continues to work the exact same way after the logout.
What Logout does is it closes a user session. The identification of a session is a cookie. If you call logout without session specified in the cookie, Logout will have no effect.
So, when you use token and make some API call, Acumatica creates a new user session for you (or use existing one if you pass the cookie).
All in all, Acumatica limits the number of open sessions. You can open multiple sessions with the same Token (if you have concurrent_access scope). You should take care of those sessions and close them properly. (or you can remove the concurrent_access and always work with the single session)
I’m running into this issues as well. Logout does not remove my API user from the Active Users list.
const logout_data = await fetch(`${acumatica_host_url}${acumatica_logout_url}`, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Set-Cookie': `ASP.NET_SessionId=${asp_session_id}`
}
});
asp_session_id contains the value of ASP.NET_SessionId that was returned during my initial login call. What I find interesting is that if you go to the Active Users table then check the source code, you’ll see that each user has a hidden session field. However, this does not match the initial session I was given during login. Either way though, when I pass either of them to the call above, my user still remains logged in.
I used WireShark for some debugging looks like the culprit was using “Set-Cookie” instead of just “cookie”.
One more thing, the documentation does not mention it, but you must pass the bearer token back too, not just the ASP.NET_SessionId cookie.
Slightly similar for direct style login as well, but you must include the “.ASPXAUTH” (the dot prefix is not a mistake) cookie in addition to the ASP.NET_SessionId cookie, which the docs do not mention.
I just ran into something similar with HTTPS/OAuth. . .
I had to hand in the session id as a cookie instead of set-cookie - probably more my lack of experience than any fault with Acumatica or the documentation here but, worth noting. That said, the lack of error message/response on the logout makes it super frustrating to work with. . .
I just ran into something similar with HTTPS/OAuth. . .
I had to hand in the session id as a cookie instead of set-cookie - probably more my lack of experience than any fault with Acumatica or the documentation here but, worth noting. That said, the lack of error message/response on the logout makes it super frustrating to work with. . .
The lack of error messages is wild in Acumatica. I personally volunteer to go in and add the appropriate error message. Like how does system tell you that one of the fields you sent over is not apart of the object...but can’t tell you which one? I’ll just blame it on C# since that’s a favorite pastime of mine :D
Do you happen to know if one needs to hand in the session id when getting a new access token?
I’ve been struggling to get Acumatica to return a refresh token so I need to be able to retrieve a new access token once it expires without triggering a new session/login.
When I specify the scope api+offline_access I get an invalid scope error rather than a refresh token. . . not sure what I’m doing wrong here considering I’m following the documentation - at least as I understand it.
I’ll just post my workflow because you should be getting a json object that looks like this
{
access_token: string,
expires_in: number,
token_type: string,
refresh_token: string,
scope: string
}
Initial login
const form = new FormData();
form.set('grant_type', 'password');
form.set('client_id', SECRET_ACUMATICA_CLIENT_ID);
form.set('client_secret', SECRET_ACUMATICA_SHARED_SECRET);
form.set('username', SECRET_ACUMATICA_USERNAME);
form.set('password', SECRET_ACUMATICA_PASSWORD);
form.set('scope', 'api offline_access');
const auth_data = await fetch(`${acumatica_host_url}${acumatica_auth_url}`, {
method: 'POST',
body: form
});
const cookies = auth_data.headers.get('set-cookie') ?? '';
const session_id = getCookie('ASP.NET_SessionId', cookies);
const token_data = await auth_data.json();
//token_data contains this
/**
{
access_token: string,
expires_in: number,
token_type: string,
refresh_token: string,
scope: string
}
*/
....
//Custom function I use to extract a cookie
function getCookie(name, cookies) {
var re = new RegExp(name + '=('^;]+)');
var value = re.exec(cookies);
return value != null ? valuel1] : '';
}
Refresh using the token_data I received above
const refresh_token = token_datad'refresh_token'];
const form = new FormData();
form.set('grant_type', 'refresh_token');
form.set('client_id', SECRET_ACUMATICA_CLIENT_ID);
form.set('client_secret', SECRET_ACUMATICA_SHARED_SECRET);
form.set('refresh_token', refresh_token);
const auth_data = await fetch(`${acumatica_host_url}${acumatica_auth_url}`, {
method: 'POST',
body: form
});
const token_data = await auth_data.json();
//token_data contains this again
/**
{
access_token: string,
expires_in: number,
token_type: string,
refresh_token: string,
scope: string
}
*/
Logout
const access_token = token_data_'access_token'];
await fetch(`${acumatica_host_url}${acumatica_logout_url}`, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
Cookie: `ASP.NET_SessionId=${session_id}`
}
});
That helps a lot! Thanks!
I was handing the scopes through incorrectly - I’m receiving the refresh token now. Thanks!
If you call logout without session specified in the cookie, Logout will have no effect.
My testing shows that this is not exactly true.
If I execute some “GET” API call with correct Token, but without session cookie, then user session will be opened. Then if I execute a logout call and pass the same Token in the “Authorization” header and do not pass session cookie, then logout call will anyway close the session successfully.
Best regards,
Andrey
If you call logout without session specified in the cookie, Logout will have no effect.
My testing shows that this is not exactly true.
If I execute some “GET” API call with correct Token, but without session cookie, then user session will be opened. Then if I execute a logout call and pass the same Token in the “Authorization” header and do not pass session cookie, then logout call will anyway close the session successfully.
Best regards,
Andrey
Are you executing this from code or an app like Postman or Thunder Client? I noticed this in my initial attempts and it turned out Thunder Client was sending the session id behind the scenes.
Are you executing this from code or an app like Postman or Thunder Client? I noticed this in my initial attempts and it turned out Thunder Client was sending the session id behind the scenes.
I’m executing this in SQL (see below code snippet), with this I am controlling what is passed into both headers “Cookie” and “Authorization”.
Also, I am recording returned headers using exec sp_OAGetProperty @GetHttpRequest, 'getAllResponseHeaders', and I’m not seeing ASP.NET_SessionId returned back from my calls.
EXEC sp_OACreate 'MSXML2.ServerXMLHTTP', @GetHttpRequest OUT
EXEC sp_OAMethod @GetHttpRequest, 'open', NULL, 'GET', @GetUrl, false
EXEC sp_OAMethod @GetHttpRequest, 'setRequestHeader', NULL, 'Cookie', @Cookies
EXEC sp_OAMethod @GetHttpRequest, 'setRequestHeader', NULL, 'Content-Type', 'application/json'
EXEC sp_OAMethod @GetHttpRequest, 'setRequestHeader', NULL, 'Connection', 'keep-alive'
EXEC sp_OAMethod @GetHttpRequest, 'setRequestHeader', NULL, 'Authorization', @AccessToken
EXEC sp_OAMethod @GetHttpRequest, 'send', NULL, NULL
Hey @eelliston ,
So basically, we need to distinguish two things here:
- Token
- Session
Your token cannot be invalidated by doing Logout and continues to work the exact same way after the logout.
What Logout does is it closes a user session. The identification of a session is a cookie. If you call logout without session specified in the cookie, Logout will have no effect.
So, when you use token and make some API call, Acumatica creates a new user session for you (or use existing one if you pass the cookie).
All in all, Acumatica limits the number of open sessions. You can open multiple sessions with the same Token (if you have concurrent_access scope). You should take care of those sessions and close them properly. (or you can remove the concurrent_access and always work with the single session)
@Dmitrii Naumov - Thanks for this! Can you provide an example for this? Our dev team and others are having an issue calling the token to properly end the session.
Thanks!
If you call logout without session specified in the cookie, Logout will have no effect.
My testing shows that this is not exactly true.
If I execute some “GET” API call with correct Token, but without session cookie, then user session will be opened. Then if I execute a logout call and pass the same Token in the “Authorization” header and do not pass session cookie, then logout call will anyway close the session successfully.
Best regards,
Andrey
@abaranovhs that depends on the ‘Concurrent Access’ API scope. If the concurrent access is not present, the token is actually enough to identify the session (since only one session is possible in that case).
@jamesh if you don’t need to have parallel open sessions, I recommend to just not request the ‘Concurrent Access’ API scope. If you do need to open multiple sessions, you do need to manage that.
E.g. if you make a new API call without Session ID defined in cookies the new session ID is opened and returned to you in the cookie. You need to log it out once you are done with that.
Hope that helps.
Hey @eelliston ,
So basically, we need to distinguish two things here:
- Token
- Session
Your token cannot be invalidated by doing Logout and continues to work the exact same way after the logout.
What Logout does is it closes a user session. The identification of a session is a cookie. If you call logout without session specified in the cookie, Logout will have no effect.
So, when you use token and make some API call, Acumatica creates a new user session for you (or use existing one if you pass the cookie).
All in all, Acumatica limits the number of open sessions. You can open multiple sessions with the same Token (if you have concurrent_access scope). You should take care of those sessions and close them properly. (or you can remove the concurrent_access and always work with the single session)
@Dmitrii Naumov - Thanks for this! Can you provide an example for this? Our dev team and others are having an issue calling the token to properly end the session.
Thanks!
Does my “Logout” example above help at all?
@charlesbcraig Have you done this successfully to close the User Sessions?
I used WireShark for some debugging looks like the culprit was using “Set-Cookie” instead of just “cookie”.
@charlesbcraig Have you done this successfully to close the User Sessions?
Yes, see above where I just needed to fix my cookie code.
Also, I no longer used Acumatica and have moved on to ERPNext. Good luck everyone!
@charlesbcraig Thanks for the response. I have faced the same issue and resolved it.
Good Luck to you as well!