I need to set a custom claim in the access_token from within a C# application. Is there a way to achive this?
So that I can create custom access_tokens on the fly.
I read though the Keycloak API reference but wan not able to find a solution.
I need this because I have a User that, depending on the application state, should get access to different ressources. I dont want to create different user to achive this. I do not want to save information into the cookies to achive this. And I also do not want to save information in URL to achive this.
I already tried to use a uma-ticket token for this as described here. But all i got was this error:
{
"error": "invalid_grant",
"error_description": "Invalid bearer token"
}
The most common option is to implement dynamic behaviour via claims. At the time of token issuance, the authorization server can reach out to an API endpoint (or database), to send account attributes and receive back custom attributes.
In Keycloak you need to use a protocol mapper for this. The last time I looked you had to develop one in Java, then configure it in the Admin UI for your client app. There is a worked example here.
This is usually a better design than trying to issue new user level access tokens on the fly. Eg an access token contains the important values used for authorization, such as role=manager or subscription_level=gold, so that the claims are trusted. The resources they grant access to could then vary a little based on runtime conditions.
Related
I am creating an identity service using IdentityServer4 and AspNetCore.Identity. The service will serve multiple websites which need to have separate users. As such I was thinking the simplest way to keep users separate is to have separate user collections in my database (in my case MongoDb), and simply use a different one based on the client_id.
I am registering my IUserRepository like so:
services.AddSingleton<IUserRepository>(x => new UserRepository(mongoClient));
I was thinking the easiest way to achieve what I want is to handle it at the DI level, so I have come up with so far is to change this to:
services.AddScoped<IUserRepository>(x => GetUserRepo(x, mongoClient));
Where GetUserRepo is a method that reads the client_id out of the request and returns a repository for the correct user collection.
This does seem to work but my issue is how "hacky" the implementation of GetUserRepo has to be:
I have to check if the request url is /connect/token and if it is, manually read the request body to find the client_id
If the user is passing a Bearer token (my identity service also includes a management API for creating users etc) then I have to manually decode the token and find the client_id claim
Really I am just wondering if there is a nicer way to do this (anything provided by IdentityServer4?) and also if this is "ok" to do at all?
The only thing I have found that could maybe help is IIdentityServerInteractionService.GetAuthorizationContextAsync however this requires a returnUrl which I don't have as I am using client credentials or resource owner password credentials methods to authenticate.
Not specifically an answer but as it might help put others on the right track:
After thinking more carefully about our scenario I realised it wasn't really necessary to do what I was trying to do. Instead each website will simply use AspNetCore.Identity to handle their own users (with their own data stores) and I am just using IdentityServer to secure my API and set each website up as a client.
I have implemented simple OAuth server with Katana using following steps:
http://www.tugberkugurlu.com/archive/simple-oauth-server-implementing-a-simple-oauth-server-with-katana-oauth-authorization-server-components-part-1
I need to log each and every API Usage so when user access any API, I have to save the generated access token and other information in database.
In GrantResourceOwnerCredentials method, Is there any way to get generated access token or is there any event in OAuthAuthorizationServerProvider where I could get it?
I have not been able to find a way to get the token in the GrantResourceOwnerCredentials method. However, if you override the TokenEndpointResponse method, you can grab the access token there. It may be a little late in the pipeline for your purposes, but it's there.
I'm building a sign-up / login flow for a web site. I plan to use Facebook as my identity provider instead of rolling my own.
I have a good feel for the server-side login flow with Facebook:
Call FB login API to get a code
Exchange the code for a user access token
Inspect the user access token
Validate the user access token details
After these steps, I'd like to check if the authenticated user is already registered in my system. If yes, simply return a newly generated bearer token, so the user can make subsequent requests to resource servers to access protected data.
If the user is not registered in the system, however, then I'd like to register them by creating a database entry. Before creating this entry though, I'd like to collect one piece of information from the user. Namely, I'd like for them to tell me their desired 'username'. I will use this unique username as my database primary key.
I'm not 100% sure on how to securely ask the user for their desired username before creating the database entry. This is my question. :)
One thought I had was to create a "redemption code". This code would be encrypted and contain the user initialization details, a secret only the server would know, and a timestamp. Something like this:
code: {
mySecret: "super-secret-value",
expirationDate: "date-value",
user: { ... },
}
After seeing the user is not in my system, I'd respond with the code + redirect the client to a page where they'd be able to specify their username. Upon submitting their username + code back up to the server, I could decrypt the code, and validate mySecret to determine the code is not tampered. If all is good, create the user in the database with the user information from the redeemed code. Lastly, I'd generate a new bearer token for the user and send it to the client.
Questions
Is my proposed redemption code strategy a secure way of requesting a username before creating the backend DB entry?
If not, what would be?
If yes, what is a secure encryption/decryption routine to use for this purpose in C#?
Flow Sequence
Steps 1-4 from above correspond to "Login" through "Validate" arrows.
My proposed redemption code strategy corresponds to the purple arrows.
Red text corresponds to Facebook specific nomenclature.
Note, Stack Overflow does something very similar to what I want to do. Before creating your account on SO, it will ask you for your desired Display Name (this happens after authenticating via Facebook, Google, etc.). After submitting your display name, your account is registered.
Use open source IdentityServer3.
Whatever flow you choose its already standardized in their server. Including (if you want or need) OpenID, OAuth2 etc.
I've created a web application that uses the OAuth authentication and universal connectors as explained in this tutorial, and started to fiddle around a little to add support for other providers like Yahoo and LinkedIn. So the authentication part works and users are created in the asp.net Membership provider. Also, all the providers return the accesstoken which I supposedly can use to retrieve more information regarding the user.
I'd really like to acquire the profile image, but it seems every provider has a different way of requesting this information. Twitter even describes a way to authorise every request by changing the HTTP header information.
Whilst reading this information on the websites of the various providers I was wondering whether this functionality isn't also already included somewhere in DotNetOpenAuth.AspNet or Microsoft.AspNet.Membership.OpenAuth implementation.
How can I use DotNetOpenAuth.AspNet and/or Microsoft.AspNet.Membership.OpenAuth to request the profile image of the loggedin user using the just acquired accesstoken?
UPDATE in response to Leo's answer
I use the following code to make a call on LinkedIn's API.
string accessToken = extraData["accesstoken"]; // Extra Data received from OAuth containing the accesstoken.
WebRequest request = WebRequest.Create("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,date-of-birth,email-address,picture-url)?oauth2_access_token=" + accessToken);
using (WebResponse response = request.GetResponse())
{
// do something with response here.
}
Error message is "The remote server returned an error: (401) Unauthorized.".
What am I doing wrong?
The answer is simple...you can't use any of these. These are wrappers of OAuth and OAuth only specifies how you can authenticate a user. Now, to request the user's profile photo you will need to use the external provider's own API and you will need most likely a valid access token. So, you will need to use one of these implementations of OAuth to authenticate a user and the recieve an access token, store the access token somewhere (usually a cookie) and then use the access token to make sub-sequent calls to the provider's APIs. Examples and links....
Facebook's Graph API allows you to retrieve users profiles
https://developers.facebook.com/docs/graph-api/quickstart/
notice that all examples in the link above will require you to include the access token in a parameter named access_token, for example
https://graph.facebook.com/me?method=GET&format=json&suppress_http_code=1&access_token={your-access-token}
Google...
https://www.googleapis.com/oauth2/v3/userinfo?access_token={your-access-token}
LinkedIn...
https://api.linkedin.com/v1/people/~:(id,first-name,last-name,date-of-birth,email-address,picture-url)?oauth2_access_token={your-access-token}
You can get more specific information from these providers' websites
Let me know if you have any other doubts I might be able to help you since I have implemented stuff like these before.
Cheers, Leo
I'm currently trying to implement the MembershipProvider class, but my user repository isn't typical to most of the examples I'm finding on the net. Instead of retrieving a user, we simply check the user's identity against an auth server for the requested URL:
User attempts to "POST" to ws.example.com/jobA
Attribute validates the user with the auth server to see if they have access to this action/url
Rejects or accepts the request
A couple other posts pointed me in this direction for implementing a custom membership provider. The way I figure it, in order to make this work, I need to be able to see what the requested URL was, and be able to look at their cookies. In Filters, i have access to the HttpRequestMessage. How do I get at the info i need in this context??
[Despite this thread is not specifically about SharePoint Membership Providers, I will just leave this solution here because I couldn't find it anywhere else, and kept being redirect to this thread while looking for solutions on Google. I hope it helps someone]
For SharePoint Membership Providers, we have the Security Token Service, which is a WCF Service. In this case, System.Web.HttpContext.Current is always null, but you can get the actual Request URL using this property:
System.ServiceModel.OperationContext.Current.RequestContext