I'm having trouble to allow users to logout from an application that uses Keycloak for access management.
I have found this topic being discussed here and there, but not clear instructions on how to handle the logout.
I tried to cause the logout of an user redirecting the browser to an endpoint of the following format:
https://example.com/auth/realms/myrealm/protocol/openid-connect/logout?id_token_hint=mytoken&post_logout_redirect_uri=https://example.com/initialpage/
What I used as "mytoken" was the access_token I had obtained making a post request to the endpoint:
https://example.com/auth/realms/playipintern/protocol/openid-connect/token
passing to it parameters like the ones bellow:
grant_type="authorization_code"
code=code_obtained_from_a_url_to_which_keycloak_redirected_the_browser
client_id=client_id_created_using_key_cloak_gui
redirect_uri=the_to_which_keycloak_redirected_the_browser
and reading the body of the response. The content of the body was a json, like the one bellow:
{
'access_token': 'long_token_I_used_latter_as_token_hint_trying_to_logout',
'expires_in': 300,
'refresh_expires_in': 1800,
'refresh_token': 'other_long_token',
'token_type': 'bearer',
'not-before-policy': 0,
'session_state': 'a_shorter_code',
'scope': 'email profile'
}
My logout attempt resulted in the following message in Keycloaks log:
22:53:51,686 WARN [org.keycloak.events] (default task-24) type=LOGOUT_ERROR, realmId=playipintern, clientId=null, userId=null, ipAddress=192.168.16.1, error=invalid_token
and the response said "We are sorry, session not active".
Now I'm aware that I should have used the id_token and not the access_token to logout, but received no id_token in the json.
Somewhere, someone said I should have included
scope=openid
in the parameters that I used to obtain the token. I did it, expecting to find an "id_token" field in the json, but nothing changed.
Someone else reported to have needed to create a scope (I believe using Keycloak's GUI) named "openid" to obtain the token. That didn't make much sense to me, but I tried it anyway and added the just created scope to the client scopes using Keycloak's GUI again. Oncemore, the json didn't change.
I tried to use the refresh_token as the id_token, but that also resulted in an invalid token message.
I don't know what to try now. Any help is appreciated.
Thank you.
/token endpoint returns only the access token by default. No refresh token is returned and no user session is created on the Keycloak side upon successful authentication by default. Due to the lack of refresh token, re-authentication is required when the access token expires. However, this situation does not mean any additional overhead for the Keycloak server because sessions are not created by default.
In this situation, logout is unnecessary. However, issued access tokens can be revoked by sending requests to the OAuth2 Revocation Endpoint as described in the OpenID Connect Endpoints section:
/realms/{realm-name}/protocol/openid-connect/revoke
Example:
POST /revoke HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
token=45ghiukldjahdnhzdauz&token_type_hint=access_token
You need to put your token in place of 45ghiukldjahdnhzdauz.
token_type_hint can take either access_token or refresh_token as value to define which type of token you want to revoke.
You will have to add scope=openid to your initial request to http://example.com/auth/realms/playipintern/protocol/openid-connect/auth (note the /auth instead of /token at the end) before the redirect from where you copied the access code.
You can find further information and explanation in this article.
Related
I have a hobby project in mind to use battle.net login. I'm wondering how I can obtain the access token from the API after receiving the authorization code.
This is Oauth flow question rather than a battle.net question.
Currently I can successfully authorize the user for my app which is registered in dev.battle.net and then I try to use the authorization code returned from the battle.net login to obtain the access token by sending a request to https://<region>.battle.net/oauth/token.
However I keep receiving this error:
{
"error": "unauthorized",
"error_description": "An Authentication object was not found in the SecurityContext"
}
I use postman extension to send post requests to that uri. I authenticate my request with my client id and secret. I pass redirect_uri (https://localhost), granty_type (authorization_code), code(the code returned from the previous authorization step). However I keep getting the error above.
I couldn't find much about battle.net online. There are other oauth related help articles but couldn't really find my way.
Wondering if you can help me with this easy stuff. I'm just wondering what I'm skipping here.
Here is the documentation:
https://dev.battle.net/docs/read/oauth
https://localhost is added in my mashery dev account's app settings.
Me again, I resolved this problem after trying almost every combination in the universe:)
Steps to apply:
Don't use the same authorization token for different access token trials, they are not valid
Always use https on every domain you test including localhost, you
redirect_uri must be https as well.
You must use the "basic authentication" in the header of your POST request while requesting the token from the authorization code you obtained from the previous step.
This is one of the most important ones: For requesting token, Pass redirect_uri, client key and secret as POST form parameters to the authenticated request. This is interesting because it's already an authenticated request; why would i need to pass my secret again? Anyways, that's how it works.
Here are the full text:
http://hakanu.net/oauth/2017/01/26/complete-guide-of-battle-net-oauth-api-and-login-button/
This is working prototype:
https://owmatch.me
Thanks.
I am getting the following error when I use the linkedin V1 API:
response body: {
"errorCode": 0,
"message": "[unauthorized]. The token used in the OAuth request has been revoked. 75--5cfb9cdb-3c9c-47c2-b3f8-XXXXXXXX",
"requestId": "I2GQ0ZMWIE",
"status": 401,
"timestamp": 1408976297742
}
I am using this guide here, I am doing exactly what this person is doing but I get a different result:
https://github.com/PrincessPolymath/LinkedIn-OAuth-Sample-Client
I have no idea why I get The token used in the OAuth request has been revoked. for an error. The HTTP request is identical. Could it be something with my bundle ID?
I cannot find anything from linkedin on the matter. Why don't linkedin have normal error-code lookups like other API's.
Here are some photos of the two request objects, one from the example and one from mine.
I'm taking a guess here based on my understanding of the problem you're describing, have not tested this. I'm also assuming you got your credentials right...
You should checkout this answer by Kamyar Mohager (#39), he explains how to bypass this error:
When obtaining access token, error occurs if:
POST https://www.linkedin.com/uas/oauth2/accessToken
Body:
{
grant_type=authorization_code,
code={auth-code},
redirect_uri={uri},
client_id={id},
client_secret={secret}
}
The error WON'T occur if you obtain the access token by passing the params as query params:
POST https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code={auth-code}&redirect_uri={uri}&client_id={id}&client_secret={secret}
Error clearly states that the user is authorized to make a call using the token which you are using.
"message": "[unauthorized]. The token used in the OAuth request has been revoked. 75--5cfb9cdb-3c9c-47c2-b3f8-XXXXXXXX",
In the two photos which you pasted above I can see that your request object has different values "tokenKey and tokenSecret" parameters than the example request object, which is correct as your request should have the token information which received from LinkedIn.
But the thing which I don't understand is why both the request objects have same values for "consumeKey & consumerSecret" parameters. I think you need to use your "consumerKey & consumerSecret" with your "tokenkey & tokensecret" to make this OAuth call. "consumer" and "token" detail combination should match then only you will be allowed to make the successful oauth call.
I guess you saw this error because you used your token with some other consumer key.
One more thing I can see that you are passing the "verifier" in your request object hence I want to know are you making a call to get the "access token" which is a 3rd leg of oauth. If yes then there could be scenario that "requestToken" is getting expired before you are making this "access_token" call as "requestToken" is actually a "temporary token" and expires quickly.
HTH...
The issue was code re-use.
As stated in the comments for the API, the API will give you a token and secret upon the first request. This only happens during authentication and then the token and secret can basically be thrown away, and the one issues at developer.linkedin can be used.
I fixed this by constructing my own request object rather than relying on the old HTTPRequestBody in the oAuth process.
I'm working on an application that integrates with GitHub and am having issues "logging out" a user that was previously authenticated. When I attempt to revoke the authorization token for the user, I get a 404 Not Found response from the API.
According to the documentation, it looks like I should just be able to make a DELETE request to https://api.github.com/authorizations/[authTokenId]. I have tried a couple of different things including:
Ensuring the Authorization header is set with the current auth token
Ensuring the UserAgent header is set with what I use for the rest of the API calls
Nothing seems to result in anything but a 404 though. I have validated that the token is valid and has that the Id matches with what is expected (id property from the authorization response and from the "check an authorization" response as well). Anyone have another thought on something I could be missing?
Looks like currently you need to include a basic authentication header (including a base64 encoded string of your username/password).
Not ideal for my purposes since I want to revoke the token when a user "logs out" of my application and I don't want to store their username/password. I've sent GitHub support an email about it to see if they have any other ideas.
Update 6/12/2013
GitHub support has stated that the above is expected at this juncture, but they are considering updating to allow revoking an authorization using the authorization as the means of authentication.
For now I'm going to require the user to enter their username/password a second time to revoke the authorization.
I followed the tutorial on https://dev.twitter.com/docs/auth/implementing-sign-twitter to use OAuth on my homepage. Everything worked and after the last step I have an oauth_token (after converting it to an access token) and an oauth_token_secret. Now I want to post a new status on twitter. So I did everything on this page https://dev.twitter.com/docs/auth/authorizing-request which is just a post request to /1/statuses/update.json. On that page nothing is said about the oauth_token_secret, so I haven't used it in my request and just have put the oauth_token in it. After submitting the post request twitter gives me the status code 401 Unauthorized. Why that? Do I have to use the oauth_token_secret somewhere?
The token secret is used to hash the signature base. Something like a password. You don't send the password, you use it to compute a secure hash of the thing the service sent to you. You send that secure hash, then the service checks that secure hash against the request you sent. If they match, you're authorized.
The gory details are described in the OAuth spec, RFC 5849.
Twitter uses OAuth1.0a, but is mostly consistent with that spec.
here's the relevant bit:
https://www.rfc-editor.org/rfc/rfc5849#section-3.4.2
A client credential grant does not return a refresh token (DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest forbids it). But ClientBase.AuthorizeRequest requires it.
Is this a bug in DotNetOpenAuth or am I doing something wrong?
I suppose I can work around by inheriting ClientBase and overriding AuthorizeRequest. Is that the correct thing to do?
Edit: It's not so easy to inherit from ClientBase outside of DotNetOpenAuth because a lot of the stuff you want is internal only. e.g. ErrorUtilities.VerifyProtocol
Edit2: Just read the draft OAuth 2 spec (draft 25) referred to in DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest and I can't find where it disallows refresh tokens for Client credential grant type. Maybe they changed it?
Google returns Refresh Token if you request it. Provide parameter in query string access_type=offline.
In my case I had to amend default Authorization Endpoint URL to: https://accounts.google.com/o/oauth2/auth?access_type=offline
Google Api C# example using DotNetOpenAuth:
private WebServerClient GetClient()
{
return new WebServerClient(
new AuthorizationServerDescription
{
AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth?access_type=offline"),
TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"),
ProtocolVersion = ProtocolVersion.V20,
},
clientIdentifier: this.settings.GoogleApisClientIdentifier,
clientSecret: this.settings.GoogleApisClientSecret
);
}
NOTE from my experience: This works only for the First request.
See Google Documentation.
I'm not sure why you say that ClientBase.AuthorizeRequest requires it. Firstly, there is an overload that only takes an access token, so it doesn't even ask for a refresh token. The overload you may have tried accepts an IAuthorizationState object, which may or may not include a refresh token, and it appears that that method only looks for a refresh token if the access token has expired. Since an expired access token can't be used, it tries to refresh it and throws if it can't. It seems reasonable to me.
Whichever method overload you choose to call, your calling mode must either avoid using expired access tokens or be prepared to respond to the exceptions that are thrown when DotNetOpenAuth or the resource server determines that they are expired or revoked. In fact since tokens can be revoked before they expire, it's a good idea to always be prepared for that.
The OAuth 2 spec draft 25 does in fact indicate that a refresh token should not be included in a response to the client credentials grant. From section 4.4.3:
4.4.3. Access Token Response
If the access token request is valid and authorized, the authorization server issues an access token as described in Section 5.1. A refresh token SHOULD NOT be included. If the request failed client authentication or is invalid, the authorization server returns an error response as described in Section 5.2.