The OAuth2 flow to use is a variation of the "Client Credentials Grant" flow from OAuth2 (see http://tools.ietf.org/html/rfc6749#section-4.4) - but instead of sending the client credentials in clear text over the wire it uses a signed JSON Web Token (JWT) assertion instead (see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06).
The concept itself is relatively simple: create a digitally signed piece of data (an assertion) that proves who the client is and then present that assertion to Google. It does although require quite a few steps to get it right.
Before we start making HTTP requests we must first acquire a set of client credentials from Google. This comes in the form of a X509 certificate which contains the private signing key for the client. To obtain this certificate we use Googles API console at https://code.google.com/apis/console. Login and go to "API access" where you click on the "Create client ID" button and select "Service account":
When your client credentials has been created you are asked to save them somewhere secure. Save them in a place where your program can load it from later.
The next step is to get Google's Token Endpoint URL. At the time of writing it is https://accounts.google.com/o/oauth2/token but this may of course change in the future.
Now we are ready to rock! First we initialize Ramone with the Google stuff:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Ramone; using Ramone.OAuth2; using Ramone.Utility.JsonWebToken; ISession Session = RamoneConfiguration.NewSession( new Uri(GoogleAPIBaseUrl)); OAuth2Settings settings = new OAuth2Settings { TokenEndpoint = new Uri(TokenEndpointUrl), ClientAuthenticationMethod = OAuth2Settings.DefaultClientAuthenticationMethods.Other }; Session.OAuth2_Configure(settings); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private static RSACryptoServiceProvider GetCryptoServiceProvider() { const string CertificatePath = "path-to-your-certificate-file" ; X509Certificate2 certificate = new X509Certificate2(CertificatePath, "notasecret" , X509KeyStorageFlags.Exportable); using (RSACryptoServiceProvider cp = (RSACryptoServiceProvider)certificate.PrivateKey) { // Create new crypto service provider that supports SHA256 (and don't ask me why the first one doesn't) CspParameters cspParam = new CspParameters { KeyContainerName = cp.CspKeyContainerInfo.KeyContainerName, KeyNumber = cp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2 }; return new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false }; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | const string Issuer = "your-client-issuer-email-address-from-google" ; const string Scope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile" ; using (RSACryptoServiceProvider csp = GetCryptoServiceProvider()) { AssertionArgs args = new AssertionArgs { Audience = TokenEndpointUrl, Issuer = Issuer, Scope = Scope }; Session.OAuth2_GetAccessTokenFromJWT_RSASHA256(csp, args); } |
If this works you are done. Ramone has authorized with Google using your client credentials without any intervention from a user.
To prove that it works we can now fetch the user name and e-mail of the current user (your client) identified by the access token returned from Google:
1 2 3 4 5 6 7 8 | Console.WriteLine( "Reading user information from Google" ); using (var response = Session.Bind( "userinfo" ).AcceptJson().Get<dynamic>()) { var body = response.Body; Console.WriteLine( "\nRESULT:" ); Console.WriteLine( "User name: " + body.name); Console.WriteLine( "E-mail: " + body.email); } |
Ingen kommentarer:
Send en kommentar