Reputation: 23
I'm having trouble obtaining a JWT from ADFS (Windows server 2012R2) using a ClientAssertionCertificate.
It all works fine when I let the user authenticate with his username and password directly into the adfs - login window, but I don't want my application to show the ADFS - login window, because the users of my application won't know the credentials. My application actually IS the user (of an api) so I want to authenticate using a certificate. When i try doing that, I get the message "The authorization server does not support the requested grant_type
. The authorization server only supports authorization_code
or refresh_token
as the grant type.
Does anyone know any workaround or other method to obtain a JWT from ADFS using a certificate? Thx a lot!
My application is a .Net 4.6.1 console application.
This is my code now:
var certPath = Path.Combine(GetCurrentDirectoryFromExecutingAssembly(), "mycertificate.pfx");
var certfile = File.OpenRead(certPath);
var certificateBytes = new byte[certfile.Length];
certfile.Read(certificateBytes, 0, (int)certfile.Length);
var cert = new X509Certificate2(
certificateBytes,
"mypassword",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
var certificate = new ClientAssertionCertificate("myclientid", cert);
AuthenticationContext context = new AuthenticationContext("https://sts.example.com/adfs",false);
AuthenticationResult authenticationResult = await context.AcquireTokenAsync("http://example.com/api", certificate);
var token = authenticationResult.AccessToken;
Upvotes: 0
Views: 1281
Reputation: 36
Have you tried using a WSTrustChannelFactory with CertificateWSTrustBinding? In the RequestSecurityToken you can specify in the TokenType that you want a JWT. The JWT you receive will be a base64 string that you need to decode.
public static async Task<string> GetAccessToken(string authority, string resource, string clientId)
{
var certPath = Path.Combine(GetCurrentDirectoryFromExecutingAssembly(), "mycertificate.pfx");
var certfile = File.OpenRead(certPath);
var certificateBytes = new byte[certfile.Length];
certfile.Read(certificateBytes, 0, (int)certfile.Length);
var cert = new X509Certificate2(
certificateBytes,
"PASSWORD",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
var factory = new WSTrustChannelFactory(
new CertificateWSTrustBinding(
SecurityMode.TransportWithMessageCredential),
"https://example.com/adfs/services/trust/13/certificatemixed") {TrustVersion = TrustVersion.WSTrust13};
if (factory.Credentials != null)
factory.Credentials.ClientCertificate.Certificate = cert;
// create token request
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference("http://example.com/api"),
KeySizeInBits = 0,
TokenType = "urn:ietf:params:oauth:token-type:jwt"
};
// request token and return
var genericXmlSecurityToken = factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
return genericXmlSecurityToken != null
? Encoding.UTF8.GetString(Convert.FromBase64String(genericXmlSecurityToken.TokenXml.InnerXml))
: string.Empty;
}
Upvotes: 2