├── ExampleWebsite ├── Bin │ ├── OAuth2Class.dll │ └── OAuth2Class.pdb ├── Web.config ├── auth.aspx ├── auth.aspx.cs ├── default.aspx ├── default.aspx.cs ├── global.asax ├── login.aspx ├── login.aspx.cs └── web.Debug.config ├── OAuth2.sln ├── OAuth2.v12.suo ├── OAuth2Class ├── OAuth2.cs ├── OAuth2Class.csproj ├── Properties │ └── AssemblyInfo.cs ├── bin │ └── Debug │ │ ├── OAuth2Class.dll │ │ └── OAuth2Class.pdb └── obj │ └── Debug │ ├── DesignTimeResolveAssemblyReferencesInput.cache │ ├── OAuth2Class.csproj.FileListAbsolute.txt │ ├── OAuth2Class.csprojResolveAssemblyReference.cache │ ├── OAuth2Class.dll │ ├── OAuth2Class.pdb │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs ├── license.md └── readme.md /ExampleWebsite/Bin/OAuth2Class.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/ExampleWebsite/Bin/OAuth2Class.dll -------------------------------------------------------------------------------- /ExampleWebsite/Bin/OAuth2Class.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/ExampleWebsite/Bin/OAuth2Class.pdb -------------------------------------------------------------------------------- /ExampleWebsite/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ExampleWebsite/auth.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="auth.aspx.cs" Inherits="auth" %> -------------------------------------------------------------------------------- /ExampleWebsite/auth.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Configuration; 3 | using System.Web.UI; 4 | 5 | public partial class auth : Page { 6 | protected void Page_Load(object sender, EventArgs e) { 7 | // We get the provider from the passed URL itself. This is configured in 8 | // the global.asax file. 9 | var provider = this.RouteData.Values["provider"].ToString(); 10 | 11 | // We fetch the clientID and clientSecret from the web.config appSettings. 12 | var clientID = WebConfigurationManager.AppSettings["OAuth2_" + provider + "_ClientID"]; 13 | var clientSecret = WebConfigurationManager.AppSettings["OAuth2_" + provider + "_ClientSecret"]; 14 | 15 | // Create a new instance of the class. Since this is the return trip-code 16 | // for this website, we don't need to give redirectURL and accessToken. 17 | var oauth2 = new FederatedLogin.OAuth2( 18 | clientID, 19 | clientSecret, 20 | provider); 21 | 22 | // Attempt to handle the response from the server and verify the login. 23 | oauth2.HandleResponse(); 24 | 25 | // If we're authenticated, store the user info. 26 | if (oauth2.IsAuthorized) { 27 | Session["OAuth2_" + provider + "_AccessToken"] = oauth2.AccessToken; 28 | Session["OAuth2_" + provider + "_UserInfo"] = oauth2.UserInfo; 29 | } 30 | 31 | // If we encountered an error, log it! 32 | if (oauth2.Error != null) { 33 | Session["OAuth2_" + provider + "_Error"] = oauth2.Error; 34 | Session["OAuth2_" + provider + "_ErrorReason"] = oauth2.ErrorReason; 35 | Session["OAuth2_" + provider + "_ErrorDescription"] = oauth2.ErrorDescription; 36 | } 37 | 38 | // Redirect back to default.aspx. 39 | Response.Redirect("/"); 40 | } 41 | } -------------------------------------------------------------------------------- /ExampleWebsite/default.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="default.aspx.cs" Inherits="_default" %> 2 | 3 | 4 | 5 | OAuth2 Example Website 6 | 7 | 8 |
9 |

10 | Login with Facebook 11 |

12 |

13 | 14 |

15 |

16 | 17 |

18 |
19 | 20 | -------------------------------------------------------------------------------- /ExampleWebsite/default.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.UI; 3 | 4 | public partial class _default : Page { 5 | protected void Page_Load(object sender, EventArgs e) { 6 | const string provider = "facebook"; 7 | 8 | var userInfo = (Session["OAuth2_" + provider + "_UserInfo"] != null ? Session["OAuth2_" + provider + "_UserInfo"] as FederatedLogin.OAuth2.OAuth2UserInfo : null); 9 | var error = (Session["OAuth2_" + provider + "_Error"] != null ? Session["OAuth2_" + provider + "_Error"].ToString() : null); 10 | var errorReason = (Session["OAuth2_" + provider + "_ErrorReason"] != null ? Session["OAuth2_" + provider + "_ErrorReason"].ToString() : null); 11 | var errorDescription = (Session["OAuth2_" + provider + "_ErrorDescription"] != null ? Session["OAuth2_" + provider + "_ErrorDescription"].ToString() : null); 12 | 13 | if (userInfo != null) 14 | this.ltInfo.Text = "Logged in as " + userInfo.Name; 15 | 16 | if (error != null) 17 | this.ltError.Text = 18 | "Error: " + error + "
\r\n" + 19 | "ErrorReason: " + errorReason + "
\r\n" + 20 | "ErrorDescription: " + errorDescription + "
\r\n"; 21 | } 22 | } -------------------------------------------------------------------------------- /ExampleWebsite/global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Language="C#" %> 2 | <%@ Import Namespace="System.Web.Routing" %> 3 | -------------------------------------------------------------------------------- /ExampleWebsite/login.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="login.aspx.cs" Inherits="login" %> -------------------------------------------------------------------------------- /ExampleWebsite/login.aspx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Configuration; 3 | using System.Web.UI; 4 | 5 | public partial class login : Page { 6 | protected void Page_Load(object sender, EventArgs e) { 7 | // We get the provider from the passed URL itself. This is configured in 8 | // the global.asax file. 9 | var provider = this.RouteData.Values["provider"].ToString(); 10 | 11 | // We fetch the clientID and clientSecret from the web.config appSettings. 12 | var clientID = WebConfigurationManager.AppSettings["OAuth2_" + provider + "_ClientID"]; 13 | var clientSecret = WebConfigurationManager.AppSettings["OAuth2_" + provider + "_ClientSecret"]; 14 | 15 | // Fetch the access token from the session, so if we've already been logged 16 | // in to Facebook, we can just refresh the token. 17 | string accessToken = null; 18 | if (Session["OAuth2_" + provider + "_AccessToken"] != null) 19 | accessToken = Session["OAuth2_" + provider + "_AccessToken"].ToString(); 20 | 21 | // Create a new instance of the class. If we don't provide the redirectURL 22 | // parameter, it will be automatically constructed as /login//auth. 23 | var oauth2 = new FederatedLogin.OAuth2( 24 | clientID, 25 | clientSecret, 26 | provider, 27 | null, 28 | accessToken); 29 | 30 | // Now we're ready to init the authentication part of our routine. If we 31 | // didn't pass in any access-token or the token isn't valid, the user will 32 | // be forwarded to the provider at this time for re-validation. 33 | oauth2.Authenticate(); 34 | 35 | // If we're authenticated, store the user info. 36 | if (oauth2.IsAuthorized) { 37 | Session["OAuth2_" + provider + "_AccessToken"] = oauth2.AccessToken; 38 | Session["OAuth2_" + provider + "_UserInfo"] = oauth2.UserInfo; 39 | } 40 | 41 | // If we encountered an error, log it! 42 | if (oauth2.Error != null) { 43 | Session["OAuth2_" + provider + "_Error"] = oauth2.Error; 44 | Session["OAuth2_" + provider + "_ErrorReason"] = oauth2.ErrorReason; 45 | Session["OAuth2_" + provider + "_ErrorDescription"] = oauth2.ErrorDescription; 46 | } 47 | 48 | // Redirect back to default.aspx. 49 | Response.Redirect("/"); 50 | } 51 | } -------------------------------------------------------------------------------- /ExampleWebsite/web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /OAuth2.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OAuth2Class", "OAuth2Class\OAuth2Class.csproj", "{79F2A6B2-EC0F-4792-8316-CC85CDE346D5}" 7 | EndProject 8 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "ExampleWebsite(1)", "http://localhost:49937", "{ED17D93D-8D8C-4CC6-9593-BF2AF425AFD5}" 9 | ProjectSection(WebsiteProperties) = preProject 10 | UseIISExpress = "true" 11 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5" 12 | ProjectReferences = "{79f2a6b2-ec0f-4792-8316-cc85cde346d5}|OAuth2Class.dll;" 13 | Debug.AspNetCompiler.VirtualPath = "/localhost_49937" 14 | Debug.AspNetCompiler.PhysicalPath = "ExampleWebsite\" 15 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_49937\" 16 | Debug.AspNetCompiler.Updateable = "true" 17 | Debug.AspNetCompiler.ForceOverwrite = "true" 18 | Debug.AspNetCompiler.FixedNames = "false" 19 | Debug.AspNetCompiler.Debug = "True" 20 | Release.AspNetCompiler.VirtualPath = "/localhost_49937" 21 | Release.AspNetCompiler.PhysicalPath = "ExampleWebsite\" 22 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_49937\" 23 | Release.AspNetCompiler.Updateable = "true" 24 | Release.AspNetCompiler.ForceOverwrite = "true" 25 | Release.AspNetCompiler.FixedNames = "false" 26 | Release.AspNetCompiler.Debug = "False" 27 | SlnRelativePath = "ExampleWebsite\" 28 | DefaultWebSiteLanguage = "Visual C#" 29 | EndProjectSection 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Release|Any CPU = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 37 | {79F2A6B2-EC0F-4792-8316-CC85CDE346D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {79F2A6B2-EC0F-4792-8316-CC85CDE346D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {79F2A6B2-EC0F-4792-8316-CC85CDE346D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {79F2A6B2-EC0F-4792-8316-CC85CDE346D5}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {ED17D93D-8D8C-4CC6-9593-BF2AF425AFD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {ED17D93D-8D8C-4CC6-9593-BF2AF425AFD5}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {ED17D93D-8D8C-4CC6-9593-BF2AF425AFD5}.Release|Any CPU.ActiveCfg = Debug|Any CPU 44 | {ED17D93D-8D8C-4CC6-9593-BF2AF425AFD5}.Release|Any CPU.Build.0 = Debug|Any CPU 45 | EndGlobalSection 46 | GlobalSection(SolutionProperties) = preSolution 47 | HideSolutionNode = FALSE 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /OAuth2.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2.v12.suo -------------------------------------------------------------------------------- /OAuth2Class/OAuth2.cs: -------------------------------------------------------------------------------- 1 | // @file 2 | // A lightweight library for OAuth2 authentication. 3 | // 4 | // @author 5 | // Stian Hanger 6 | // 7 | // @url 8 | // https://github.com/nagilum/OAuth2Csharp 9 | 10 | using System; 11 | using System.Collections.Generic; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Net; 15 | using System.ServiceModel; 16 | using System.Web; 17 | using System.Web.Script.Serialization; 18 | 19 | namespace FederatedLogin { 20 | /// 21 | /// Authorization, refresh, and validation of users through OAuth2. 22 | /// 23 | public class OAuth2 { 24 | /// 25 | /// A list of pre-defined provider endpoints. 26 | /// 27 | private readonly List endpoints = new List { 28 | new OAuth2Endpoint { 29 | Provider = "Facebook", 30 | AuthURL = "https://graph.facebook.com/oauth/authorize", 31 | AccessTokenURL = "https://graph.facebook.com/oauth/access_token", 32 | RefreshTokenURL = "https://graph.facebook.com/oauth/client_code", 33 | UserInfoURL = "https://graph.facebook.com/me" 34 | } 35 | }; 36 | 37 | /// 38 | /// The current request object to use throughout the library. 39 | /// 40 | private readonly HttpRequest request = HttpContext.Current.Request; 41 | 42 | /// 43 | /// The current response object to use throughout the library. 44 | /// 45 | private readonly HttpResponse response = HttpContext.Current.Response; 46 | 47 | /// 48 | /// ClientID given by provider. 49 | /// 50 | private string clientID { get; set; } 51 | 52 | /// 53 | /// ClientSecret issued by provider. 54 | /// 55 | private string clientSecret { get; set; } 56 | 57 | /// 58 | /// Name of provider. 59 | /// 60 | private string provider { get; set; } 61 | 62 | /// 63 | /// URL for provider to redirect back to when auth is completed. 64 | /// 65 | private string redirectURL { get; set; } 66 | 67 | /// 68 | /// Access token issued by provider. 69 | /// 70 | public string AccessToken { get; private set; } 71 | 72 | /// 73 | /// Expiration date of the issued access token. 74 | /// 75 | public DateTime AccessTokenExpiration { get; private set; } 76 | 77 | /// 78 | /// The type of token issued by the provider. 79 | /// 80 | public string TokenType { get; set; } 81 | 82 | /// 83 | /// Reflects whether or not the user has been authorized. 84 | /// 85 | public bool IsAuthorized { get; private set; } 86 | 87 | /// 88 | /// Parsed user-info from serialized info from provider. 89 | /// 90 | public OAuth2UserInfo UserInfo { get; private set; } 91 | 92 | /// 93 | /// Serialized string of the user-info response from provider. 94 | /// 95 | public string UserInfoSerialized { get; private set; } 96 | 97 | /// 98 | /// General error message from provider. 99 | /// 100 | public string Error { get; set; } 101 | 102 | /// 103 | /// Reason for error, from provider. 104 | /// 105 | public string ErrorReason { get; set; } 106 | 107 | /// 108 | /// Description of error, from provider. 109 | /// 110 | public string ErrorDescription { get; set; } 111 | 112 | /// 113 | /// Initiate a new instance of the OAuth2 library. 114 | /// 115 | /// ClientID given by provider. 116 | /// ClientSecret issued by provider. 117 | /// Name of provider. 118 | /// URL for provider to redirect back to when auth is completed. 119 | /// (optional) Access token to refresh. 120 | public OAuth2(string clientID, string clientSecret, string provider, string redirectURL = null, string accessToken = null) { 121 | if (string.IsNullOrWhiteSpace(clientID) || 122 | string.IsNullOrWhiteSpace(clientSecret)) 123 | throw new MissingFieldException("Both clientID and clientSecret are required!"); 124 | 125 | var endpoint = 126 | this.endpoints.SingleOrDefault(ep => ep.Provider.Equals(provider, StringComparison.CurrentCultureIgnoreCase)); 127 | 128 | if (endpoint == null) 129 | throw new EndpointNotFoundException("Missing endpoint for given provider: " + provider); 130 | 131 | if (string.IsNullOrWhiteSpace(redirectURL)) 132 | redirectURL = 133 | this.request.Url.Scheme + 134 | "://" + 135 | this.request.Url.Authority + 136 | "/login/" + provider + "/auth"; 137 | 138 | this.clientID = clientID; 139 | this.clientSecret = clientSecret; 140 | this.provider = provider; 141 | this.redirectURL = redirectURL; 142 | 143 | this.AccessToken = accessToken; 144 | } 145 | 146 | /// 147 | /// Add an endpoint. 148 | /// 149 | /// Name of the provider. 150 | /// URL for user-redirection to provider auth-page. 151 | /// URL for access token validation. 152 | /// URL for access token refresh. 153 | /// URL for user infomation gathering. 154 | /// Provider-scope, if any. 155 | public void AddEndpoint(string provider, string authURL, string accessTokenURL, string refreshTokenURL, string userInfoURL, string scope = null) { 156 | this.endpoints.Add( 157 | new OAuth2Endpoint { 158 | Provider = provider, 159 | AuthURL = authURL, 160 | Scope = scope 161 | }); 162 | } 163 | 164 | /// 165 | /// Redirect the user to the providers auth-page, or attempt to re-validate the stored access-token. 166 | /// 167 | public void Authenticate() { 168 | List> parameters; 169 | string url; 170 | 171 | var endpoint = 172 | this.endpoints.Single(ep => ep.Provider.Equals(provider, StringComparison.CurrentCultureIgnoreCase)); 173 | 174 | if (!string.IsNullOrWhiteSpace(this.AccessToken)) { 175 | parameters = new List> { 176 | new Tuple("access_token", this.AccessToken), 177 | new Tuple("client_id", this.clientID), 178 | new Tuple("client_secret", this.clientSecret), 179 | new Tuple("redirect_uri", this.redirectURL) 180 | }; 181 | 182 | url = 183 | endpoint.RefreshTokenURL + "?" + 184 | this.buildQueryString(parameters); 185 | 186 | var resp = this.makeWebRequest(url); 187 | var code = ""; 188 | 189 | try { 190 | code = new JavaScriptSerializer().Deserialize(resp).Code; 191 | } 192 | catch (Exception ex) { 193 | this.Error = "Unable to parse JSON response."; 194 | this.ErrorDescription = ex.Message; 195 | } 196 | 197 | if (!string.IsNullOrWhiteSpace(code)) 198 | this.handleCodeResponse(code); 199 | 200 | if (this.IsAuthorized) 201 | return; 202 | } 203 | 204 | parameters = new List> { 205 | new Tuple("client_id", this.clientID), 206 | new Tuple("display", "page"), 207 | new Tuple("locale", "en"), 208 | new Tuple("redirect_uri", this.redirectURL), 209 | new Tuple("response_type", "code") 210 | }; 211 | 212 | if (!string.IsNullOrWhiteSpace(endpoint.Scope)) 213 | parameters.Add( 214 | new Tuple("scope", endpoint.Scope)); 215 | 216 | url = 217 | endpoint.AuthURL + "?" + 218 | this.buildQueryString(parameters); 219 | 220 | this.response.Redirect(url, true); 221 | } 222 | 223 | /// 224 | /// Check for OAuth2 code response and attempt to validate it. 225 | /// 226 | public void HandleResponse() { 227 | if (this.request.QueryString["code"] == null) 228 | return; 229 | 230 | var code = this.request.QueryString["code"]; 231 | var error = this.request.QueryString["error"]; 232 | 233 | if (!string.IsNullOrWhiteSpace(code)) { 234 | this.handleCodeResponse(code); 235 | } 236 | else if (!string.IsNullOrWhiteSpace(error)) { 237 | this.Error = error; 238 | this.ErrorReason = this.request.QueryString["error_reason"]; 239 | this.ErrorDescription = this.request.QueryString["error_description"]; 240 | } 241 | } 242 | 243 | /// 244 | /// Validate a user by checking the 'code' variable against the provider. 245 | /// 246 | /// Code to validate. 247 | private void handleCodeResponse(string code) { 248 | var parameters = new List> { 249 | new Tuple("client_id", this.clientID), 250 | new Tuple("redirect_uri", this.redirectURL), 251 | new Tuple("client_secret", this.clientSecret), 252 | new Tuple("code", code) 253 | }; 254 | 255 | var endpoint = 256 | this.endpoints.Single(ep => ep.Provider.Equals(provider, StringComparison.CurrentCultureIgnoreCase)); 257 | 258 | var url = 259 | endpoint.AccessTokenURL + "?" + 260 | this.buildQueryString(parameters); 261 | 262 | var resp = this.makeWebRequest(url); 263 | 264 | if (this.Error != null) 265 | return; 266 | 267 | this.analyzeAccessTokenResponse(resp); 268 | 269 | if (string.IsNullOrWhiteSpace(this.AccessToken) && 270 | !this.IsAuthorized) 271 | return; 272 | 273 | parameters = new List> { 274 | new Tuple("access_token", this.AccessToken) 275 | }; 276 | 277 | url = 278 | endpoint.UserInfoURL + "?" + 279 | this.buildQueryString(parameters); 280 | 281 | resp = this.makeWebRequest(url); 282 | this.analyzeUserInfoResponse(resp); 283 | } 284 | 285 | /// 286 | /// Attempt to analyze access-token response, either in string or JSON format. 287 | /// 288 | /// Strong or JSON response. 289 | private void analyzeAccessTokenResponse(string resp) { 290 | if (resp == null) 291 | return; 292 | 293 | this.AccessToken = null; 294 | this.AccessTokenExpiration = DateTime.MinValue; 295 | 296 | if (resp.StartsWith("{") && 297 | resp.EndsWith("}")) { 298 | try { 299 | var cr = new JavaScriptSerializer().Deserialize(resp); 300 | 301 | if (!string.IsNullOrWhiteSpace(cr.Access_Token)) 302 | this.AccessToken = cr.Access_Token; 303 | 304 | if (cr.Expires_In > 0) 305 | this.AccessTokenExpiration = DateTime.Now.AddSeconds(cr.Expires_In); 306 | 307 | if (!string.IsNullOrWhiteSpace(cr.Token_Type)) 308 | this.TokenType = cr.Token_Type; 309 | } 310 | catch (Exception ex) { 311 | this.Error = "Unable to parse JSON response."; 312 | this.ErrorDescription = ex.Message; 313 | } 314 | } 315 | else { 316 | foreach (var entry in resp.Split('&')) { 317 | if (entry.IndexOf('=') == -1) 318 | continue; 319 | 320 | var key = entry.Substring(0, entry.IndexOf('=')); 321 | var val = entry.Substring(entry.IndexOf('=') + 1); 322 | 323 | switch (key) { 324 | case "access_token": 325 | this.AccessToken = val; 326 | break; 327 | 328 | case "expires": 329 | case "expires_in": 330 | int exp; 331 | if (int.TryParse(val, out exp)) 332 | this.AccessTokenExpiration = DateTime.Now.AddSeconds(exp); 333 | 334 | break; 335 | 336 | case "token_type": 337 | this.TokenType = val; 338 | break; 339 | } 340 | } 341 | } 342 | 343 | this.IsAuthorized = (!string.IsNullOrWhiteSpace(this.AccessToken) && 344 | this.AccessTokenExpiration > DateTime.Now); 345 | } 346 | 347 | /// 348 | /// Attempt to analyze the user-info JSON object from provider. 349 | /// 350 | /// Serialized JSON object. 351 | private void analyzeUserInfoResponse(string resp) { 352 | if (resp == null) 353 | return; 354 | 355 | this.UserInfoSerialized = resp; 356 | 357 | try { 358 | this.UserInfo = new JavaScriptSerializer().Deserialize(resp); 359 | } 360 | catch (Exception ex) { 361 | this.Error = "Unable to parse JSON response."; 362 | this.ErrorDescription = ex.Message; 363 | } 364 | } 365 | 366 | /// 367 | /// Compiles a list of parameters into a working query-string. 368 | /// 369 | /// Parameters to compile. 370 | /// Compilled query-string. 371 | private string buildQueryString(IEnumerable> parameteres) { 372 | return 373 | parameteres.Aggregate("", (current, parameter) => current + ("&" + parameter.Item1 + "=" + HttpUtility.UrlEncode(parameter.Item2))) 374 | .Substring(1); 375 | } 376 | 377 | /// 378 | /// Perform a HTTP web request to a given URL. 379 | /// 380 | /// URL to request. 381 | /// String of response. 382 | private string makeWebRequest(string url) { 383 | try { 384 | var req = WebRequest.Create(url); 385 | var res = req.GetResponse(); 386 | var httpres = res as HttpWebResponse; 387 | var status = 0; 388 | 389 | if (httpres != null) 390 | status = (int)httpres.StatusCode; 391 | 392 | if (status != 200) 393 | return null; 394 | 395 | var stream = res.GetResponseStream(); 396 | 397 | if (stream == null) 398 | return null; 399 | 400 | var reader = new StreamReader(stream); 401 | var resp = reader.ReadToEnd(); 402 | 403 | reader.Close(); 404 | stream.Close(); 405 | 406 | return resp; 407 | } 408 | catch (Exception ex) { 409 | this.Error = "Unable to properly make HTTP request."; 410 | this.ErrorDescription = ex.Message; 411 | } 412 | 413 | return null; 414 | } 415 | 416 | /// 417 | /// Endpoint to use for validation. 418 | /// 419 | private class OAuth2Endpoint { 420 | /// 421 | /// Name of provider. 422 | /// 423 | public string Provider { get; set; } 424 | 425 | /// 426 | /// URL for user-redirection to provider auth-page. 427 | /// 428 | public string AuthURL { get; set; } 429 | 430 | /// 431 | /// URL for access token validation. 432 | /// 433 | public string AccessTokenURL { get; set; } 434 | 435 | /// 436 | /// URL for access token refresh. 437 | /// 438 | public string RefreshTokenURL { get; set; } 439 | 440 | /// 441 | /// URL for user infomation gathering. 442 | /// 443 | public string UserInfoURL { get; set; } 444 | 445 | /// 446 | /// Provider-scope, if any. 447 | /// 448 | public string Scope { get; set; } 449 | } 450 | 451 | /// 452 | /// Object for json parsed code-response from provider. 453 | /// 454 | private class OAuth2CodeResponse { 455 | /// 456 | /// Code from provider. 457 | /// 458 | public string Code { get; set; } 459 | 460 | /// 461 | /// Token issued by the provider. 462 | /// 463 | public string Access_Token { get; set; } 464 | 465 | /// 466 | /// Amount of second til token expires. 467 | /// 468 | public int Expires_In { get; set; } 469 | 470 | /// 471 | /// The type of token issued by the provider. 472 | /// 473 | public string Token_Type { get; set; } 474 | } 475 | 476 | /// 477 | /// Object to store providers user-info. 478 | /// 479 | public class OAuth2UserInfo { 480 | /// 481 | /// ID issued by provider. 482 | /// 483 | public string ID { get; set; } 484 | 485 | /// 486 | /// E-mail for user. 487 | /// 488 | public string Email { get; set; } 489 | 490 | /// 491 | /// First name of user. 492 | /// 493 | public string FirstName { get; set; } 494 | 495 | /// 496 | /// First name of user. 497 | /// 498 | public string First_Name { get; set; } 499 | 500 | /// 501 | /// Last name of user. 502 | /// 503 | public string LastName { get; set; } 504 | 505 | /// 506 | /// Last name of user. 507 | /// 508 | public string Last_Name { get; set; } 509 | 510 | /// 511 | /// Full name of user. 512 | /// 513 | public string Name { get; set; } 514 | 515 | /// 516 | /// Gender of user. 517 | /// 518 | public string Gender { get; set; } 519 | 520 | /// 521 | /// Locale of user. 522 | /// 523 | public string Locale { get; set; } 524 | 525 | /// 526 | /// Time-zone of user. 527 | /// 528 | public int TimeZone { get; set; } 529 | 530 | /// 531 | /// Username of user. 532 | /// 533 | public string Username { get; set; } 534 | } 535 | } 536 | } -------------------------------------------------------------------------------- /OAuth2Class/OAuth2Class.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {79F2A6B2-EC0F-4792-8316-CC85CDE346D5} 8 | Library 9 | Properties 10 | OAuth2Class 11 | OAuth2Class 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | -------------------------------------------------------------------------------- /OAuth2Class/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OAuth2Class")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("OAuth2Class")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a3651757-3052-48e9-bdb1-fa16621726ec")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /OAuth2Class/bin/Debug/OAuth2Class.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/bin/Debug/OAuth2Class.dll -------------------------------------------------------------------------------- /OAuth2Class/bin/Debug/OAuth2Class.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/bin/Debug/OAuth2Class.pdb -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/OAuth2Class.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\stianh\Documents\GitHub\OAuth2\OAuth2Class\bin\Debug\OAuth2Class.dll 2 | C:\Users\stianh\Documents\GitHub\OAuth2\OAuth2Class\bin\Debug\OAuth2Class.pdb 3 | C:\Users\stianh\Documents\GitHub\OAuth2\OAuth2Class\obj\Debug\OAuth2Class.csprojResolveAssemblyReference.cache 4 | C:\Users\stianh\Documents\GitHub\OAuth2\OAuth2Class\obj\Debug\OAuth2Class.dll 5 | C:\Users\stianh\Documents\GitHub\OAuth2\OAuth2Class\obj\Debug\OAuth2Class.pdb 6 | -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/OAuth2Class.csprojResolveAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/OAuth2Class.csprojResolveAssemblyReference.cache -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/OAuth2Class.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/OAuth2Class.dll -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/OAuth2Class.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/OAuth2Class.pdb -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /OAuth2Class/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nagilum/-DEPRECATED-OAuth2Csharp/54bb143bbecf5b3302e30fcf953b9c9d26dd0151/OAuth2Class/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Stian Hanger 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | 3 | This code is rather messy and I've written a more lean version over at https://github.com/nagilum/oauth2-csharp 4 | 5 | 6 | 7 | ## OAuth2 lib for Csharp 8 | 9 | A lightweight library for OAuth2 authentication. 10 | 11 | Requirements 12 | ------------ 13 | 14 | The only file in the given solution that is nessecary is the OAuth2.cs file in the OAuth2Class folder. 15 | The rest is just added as an example of how you can structure the entire thing, either use is as a direct .cs file or as a assembly DLL. 16 | 17 | Usage 18 | ----- 19 | 20 | Put this code on the login page: 21 | 22 | ```csharp 23 | var clientID = 'your-apps-client-id'; 24 | var clientSecret = 'your-apps-client-secret'; 25 | var provider = 'provider to use'; 26 | 27 | // This is the URL the provider will send the user back to after authorization. 28 | // If you set this to null it will be constructed using the URL authority and 29 | // sub-path /login//auth 30 | var redirectURL = 'url-for-provider-return'; 31 | 32 | // If you have the users access-token from a previous login with the same 33 | // provider, you can suply it here and the lib will try to refresh it so the 34 | // user don't have to take the round-trip to the provider. Set this to null 35 | // if you don't have it. 36 | var accessToken = 'stored-access-token-for-user'; 37 | 38 | var oauth2 = new OAuth2( 39 | clientID, 40 | clientSecret, 41 | provider, 42 | redirectURL, 43 | accessToken); 44 | 45 | // This will try and refresh the access token if you specified id, if not, the 46 | // user will be forwarded to the providers login-page for authorization and 47 | // the request stops here. 48 | oauth2.Authenticate(); 49 | 50 | if (oauth2.IsAuthorized) { 51 | // This code will trigger if the access-token was simply refreshed (and is 52 | // still valid). So here you can proceed with normal access-granted stuff. 53 | } 54 | ``` 55 | 56 | Put this code on the auth page: 57 | 58 | ```csharp 59 | var clientID = 'your-apps-client-id'; 60 | var clientSecret = 'your-apps-client-secret'; 61 | var provider = 'provider to use'; 62 | 63 | var oauth2 = new OAuth2( 64 | clientID, 65 | clientSecret, 66 | provider, 67 | redirectURL, 68 | accessToken); 69 | 70 | // Attempt to validate the code-response from the provider and retrieve a valid 71 | // access-token. 72 | oauth2.HandleResponse(); 73 | 74 | if (oauth2.IsAuthorized) { 75 | // If the lib received a valid access-token, this code will trigger, and you 76 | // can go about your business as normal. 77 | } 78 | ``` 79 | 80 | Properties 81 | ---------- 82 | 83 | **AccessToken** (string) 84 | 85 | The valid access token issued by the provider. 86 | 87 | **AccessTokenExpiration** (DateTime) 88 | 89 | Exact date-time when the access token expires. 90 | 91 | **TokenType** (string) 92 | 93 | Which type of token the provider issued. f.eks: Bearer, so you can use it for 94 | API calls and the like. 95 | 96 | **IsAuthorized** (bool) 97 | 98 | Indicating whether or not the authentication process was completed and the user 99 | was successfully authorized by the provider, aka the go-signal. 100 | 101 | **UserInfo** (class) 102 | 103 | Formatted collection of user-information provided by the provider. 104 | 105 | **UserInfoSerialized** (string) 106 | 107 | Serialized JSON from the provider with user-info which was used to parse 108 | formatted info to the UserInfo class. 109 | 110 | **Error**, **ErrorReason**, and **ErrorDescription** (string) 111 | 112 | If an error occurred during the auth process, this is where the info about it 113 | will be. 114 | 115 | Additional Functions 116 | -------------------- 117 | 118 | **AddEndpoint** 119 | 120 | You can use this function to programatically add additional endpoints for use. 121 | Obviously this has to be done prior to calling the ```Authenticate()``` function. 122 | 123 | ```csharp 124 | oauth2.AddEndpoint( 125 | 'provider-name', 126 | 'auth-url', // URL for user-redirection to provider auth-page. 127 | 'access-token-url', // URL for access token validation. 128 | 'refresh-token-url', // URL for access token refresh. 129 | 'user-info-url', // URL for user infomation gathering. 130 | 'scope' // Provider-scope, if any. 131 | ); 132 | ``` 133 | --------------------------------------------------------------------------------