I have already implemented my own IPersistedGrantStore called PostgresPersistedGrantStore that stores grant in my postgresql database and it works really great.
Now i want to move really forward and i want to get the refresh token from the key that is stored in my postgresql table. But from what i read it is not a proper refreshtoken but a hash to protect the refreshtoken. Is there a way to decrypt, read the refresh token from the key property, using maybe a fuction from the identityserver api?
I am trying to implement my own impersonation workflow, so it would be easy to login as any user using the latest refresh token that exists persisted in my db
A long time has passed since the question had been asked, but I think I'm sharing a relevant information.
Here is the method which is implemented at IdentityServer4.Stores.DefaultGrantStore<T> and actually creates the key for the refresh token.
protected virtual string GetHashedKey(string value)
{
return (value + KeySeparator + GrantType).Sha256();
}
Where
value is the actual value of the refresh token,
KeySeparator is a
constant string field defined at the same class, the
value is ":",
GrantType is 'refresh_token' in this particular case.
This method is being used while creating/validating the refresh token.
I think this information clearly states that there is no way to get the refresh token value by using the key.
Reference:
https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/src/Stores/Default/DefaultGrantStore.cs#L77
Identity Server 4 has a build-in endpoint for this - <server_url>/Connect/Token.
You need to send a POST request to this endpoint, with x-www-form-urlencoded body type, which contains:
refresh_token: current refresh_token
client_id: the client that you are refreshing the token for
client_secret: the secret of the client
grant_type: refresh_token
It will give you back a "refreshed" access_token along with a new refresh_token.
The initial refresh_token you should have received once you have logged in. Have in mind - once refresh_token is used (to get a new access_token) it gets invalidated. This is why you are receiving a new with every request to the endpoint.
Here is some more info about the refresh_token itself.
And here - about the token endpoint.
Related
I'm pretty new to FastAPI and OAuth2 in general. I just worked through the tutorial "Simple OAuth2 with Password and Bearer" and it mostly made sense, but there was one step that felt like magic to me..
How does the access token get stored onto the client and subsequently get passed into the client's requests?
My understanding of the flow is that it's basically
User authenticates with their username and password (these get POST'ed to the /token endpoint).
User's credentials are validated, and the /token endpoint returns the access token (johndoe) inside some JSON. (This is how the user receives his access token)
???
User make a subsequent request to a private endpoint, like GET /users/me. The user's request includes the header Authorization: Bearer johndoe. (I don't think the docs mention this, but it's what I've gathered from inspecting the request in Chrome Developer Tools)
The authorization token is then used to lookup the user who made the request in (4)
Step (3) is the part that I don't understand. How does the access token seemingly get stored on the client, and then passed as a header into the next request?
Demo
When you run the code in the tutorial, you get the following swagger docs. (Note the Authorize button.)
I click Authorize and enter my credentials. (username: johndoe, password: secret)
And now I can access the /users/me endpoint.
Notice how the header Authorization: Bearer johndoe was automagically included in my request.
Last notes:
I've checked my cookies, session storage, and local storage and all are empty
The authorization header disappears if I refresh the page or open a new tab
I suspect Swagger is doing something under the hood here, but I can't put my finger on it.
If you need persistence for the token you'd usually use localStorage or similar, but in SwaggerUIs specific case, the authentication information is kept internally in the library.
If you have enabled persistence SwaggerUI will persistent the access token to localStorage:
export const persistAuthorizationIfNeeded = () => ( { authSelectors, getConfigs } ) => {
const configs = getConfigs()
if (configs.persistAuthorization)
{
const authorized = authSelectors.authorized()
localStorage.setItem("authorized", JSON.stringify(authorized.toJS()))
}
}
I am integration Salesforce OAuth in my application. After mapping users' Salesforce account with our application account I saved access token in DB. When user make request to fetch data from his Salesforce account I just use that token to get data. Sadly, token has expiration time (max 24 hrs). After token is expired user has to again connect salesforce account with our app.
Is there anyway to keep salesforce session alive for unlimited time or any other way to avoid repeated login?
I think what you are looking for is a Refresh Token process. Although you can control the expiration time, as you said there is certain limits you can't pass. Instead you can send a request to your org that can obtain new Session ID for you.
Example:
POST /services/oauth2/token HTTP/1.1
Host: https://login.salesforce.com/
grant_type=refresh_token&client_id=3MVG9lKcPoNINVBIPJjdw1J9LLM82HnFVVX19KY1uA5mu0
QqEWhqKpoW3svG3XHrXDiCQjK1mdgAvhCscA9GE&client_secret=1955279925675241571
&refresh_token=***your token here***
Note that this does not work if you are using username-password OAuth authentication flow. Check this dev documentation for the parameters you can use for Refresh Tokens and what responses can it return. - https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_understanding_refresh_token_oauth.htm
It is not possible to make sure that user session never expires. However, you can setup the session timeout value to a maximum of 24 hours.
I agree with Iojo. I implemented the similar requirement to save the Token in DB and reused it for multiple API callouts.
Note: In my case - for all the API callouts - Authentication layer are taken care by same middleware. Additionally, I am using username-password for access token where, clearly, I cannot use refresh token.
What I did for Access Token with token
saved in DB?
//Please create a re-usable method in the Rest handler to Retrieve Token
private string getToken(){
If(Token created within Session Timeout Limit){
//Use encrypted token given in the DB
}
else{
//reuse code to generate new token
//save the encrypted token in the DB for future use
}
}
Benefits:
You need to generate Token just one time within given Session Timeout Limit
Re-use the same if there are multiple API calls in salesforce
Question
How does User.Identity.GetUserId() finds the current user's Id?
Does it find the user Id from the Cookies, or does it query the database? Or any other methods?
Problem
For some reason, User.Identity.GetUserId() returns null when I add a valid Bearer Token to my Http request header and send the request to my controller's endpoint:
// MVC Controller Action Method
[Authorize]
public HttpResponseMessage(UserInfoViewModel model)
{
// Request passes the Authorization filter since a valid oauth token
// is attached to the request header.
string userId = User.Identity.GetUserId();
// However, userId is null!
// Other stuff...
}
How does User.Identity.GetUserId() finds the current user's Id?
ClaimTypes.NameIdentifier is the claim used by the function User.Identity.GetUserId()
You would need to add the claim in your authorization code,
identity.AddClaim(ClaimTypes.NameIdentifier, user.Id);
identity is of type ClaimIdentity.
When the user is logged into your app, the server, using ASP.NET Identity, validates your user using DB and creates a valid token that returns to the UI. This token will be valid to its expiration and has inside all information needed to authenticate and authorize the user, including the user's Id. Next calls from client side to server side must be done using this token in the http request header, but server will not call the DB again, because ASP.NET identity knows how to decrypt the token and get all the information of your user.
The use of cookies is only a way to store the token in the client side. As I commented above, you have to send the token on the next requests after the login, so you can store this token in cookies or in Session Storage in your browser.
First, make sure you're not allowing for non-authenticated users.
After that, you want to parse Bearer tokens you have to configure it.
You're going to the need this package Microsoft.Owin.Security.OAuth
And at startup if have to configure ASP.NET Identity to use Bearer Authentication with:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions {
// your options;
});
Probably on your StartupAuth.cs file
I'm working on a Web Application that allows user to connect AdWords account.
1) So once user connected their AW account I am getting token from AW API that includes an access token and a refresh token. So far so good, it's just a typical OAuth2 process.
2) Next time another user connects same AW account, AW would not provide me with a refresh token, assuming I have it stored somewhere, which is expected.
So here is the problem, there doesn't seem to be a way to get user information without the refresh token, meaning I can't identify the user to retrieve the refresh token.
I'm using .NET library (Google.Apis.Analytics.v3) and it doesn't allow me to request customer information without providing the refresh token...
Here is the sample code:
var tokenResponse = await adWordsService.ExchangeCodeForTokenAsync(code, redirectUri);
var adWordsUser = adWordsService.GetAdWordsUser();
var customerService = (CustomerService)adWordsUser.GetService(AdWordsService.v201502.CustomerService);
var customer = customerService.get();
adWordsService is just a wrapper around the API.
so when I execute this line var customer = customerService.get() I get a following error:
ArgumentNullException: Value cannot be null.
Parameter name: AdWords API requires a developer token. If you don't have one, you can refer to the instructions at https://developers.google.com/adwords/api/docs/signingup to get one.
Google.Api.Ads.AdWords.Lib.AdWordsSoapClient.InitForCall(String methodName, Object[] parameters)
Developer token is there and so are all the client IDs.
If I add this line adWordsUser.Config.AuthToken = tokenResponse.AccessToken; before making the call, it complains about the refresh token.
ArgumentNullException: Value cannot be null.
Parameter name: Looks like your application is not configured to use OAuth2 properly. Required OAuth2 parameter RefreshToken is missing. You may run Common\Utils\OAuth2TokenGenerator.cs to generate a default OAuth2 configuration.
Google.Api.Ads.Common.Lib.OAuth2ProviderBase.ValidateOAuth2Parameter(String propertyName, String propertyValue)
So the question is, how does one acquire user information (in this case customerId, according to this article https://developers.google.com/adwords/api/docs/guides/optimizing-oauth2-requests#authenticating_multiple_accounts) during authentication for the purpose of storing the refresh token?
So I just found the problem is in the adWordsService. When the AdWordsUser is created it isn't assigned the updated authentication provider which contains the latest authentication token. Once this authentication provider is added the AdWordsUser doesn't try to refresh the token since the token hasn't expired yet, thus there is no need for the refresh token.
I just started to work on wcf service build an web application to consume my service . I made that token based i pass token in every request and then check that token on each request from database that its valid or not . I think this is not good to send an extra request to db every time . So , is this possible to authenticate user first time when he login or first make request to service and after that until session remain all my requests work with token ?
I searched on google but every one was telling how to authenticate with service .
Instead of a random string that you generate and need to check in the database, make your tokens around encryption and/or signing just like many authentication modules do.
In other words, build a token from a user/application name, issue date and/or expiry date, encrypt it and you have a self-contained token that doesn't need any database lookups for validation.
For easy encryption, the MachineKey can be used
http://msdn.microsoft.com/en-us/library/system.web.security.machinekey%28v=vs.110%29.aspx
A side note - this is how forms authentication / session authentication modules work. You have cookies (tokens) that carry the authentication information. You could consider switching to these.
Edit: an example you ask about:
// create token
string username = "foo";
string token = Convert.ToBase64String( MachineKey.Protect(
Encoding.UTF8.GetBytes( username ) ) );
// get username out of token
string token = ....;
string username = Encoding.UTF8.GetString( MachineKey.Unprotect(
Convert.FromBase64String( token ) ) );
Checking the Auth token with the database on each request is probably a bad idea. What is commonly used as a token is the current user principal itself but serialized and encrypted.
The token is generated and returned to the client upon login. Then on each request you pass the token the service which then gives you the opportunity to deserialize it and populate your System.Threading.Thread.CurrentPrincipal without a roundtrip to the DB.
Check these SO answers for more insight
Delivering a JWT SecurityToken to a WCF client
How to use Microsoft JWT Token Handler to secure webHttpBinding based WCF service