OAuth 2.0
The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf.
The main features of the Tizen.Account.OAuth2 namespace includes the following:
-
Creating an OAuth 2.0 request
You can create a request handle, set and retrieve request parameters, and pass the request to the OAuth 2.0 manager to request a token.
-
Sending the request to the server to ask for a grant or token
You can request the authorization server for the required OAuth 2.0 grant or token using various methods and grant types.
-
Managing the server response
You can obtain information from the OAuth 2.0 response handle returned in a callback.
Figure: Protocol flow
The OAuth 2.0 specification is defined in [RFC 6749] and it builds on the OAuth 1.0 [RFC 5849] deployment experience, as well as additional use cases and extensibility requirements gathered from the wider IETF community. The OAuth 2.0 protocol is not backward-compatible with OAuth 1.0.
Authorization grant
An authorization grant is a credential representing the resource owner’s authorization (to access its protected resources) used by the client to obtain an access token.
The specification defines the following 4 grant types, as well as an extensibility mechanism for defining additional types:
-
Authorization code
The authorization code is obtained by using an authorization server as an intermediary between the client and resource owner. Instead of requesting authorization directly from the resource owner, the client directs the resource owner to an authorization server, which in turn directs the resource owner back to the client with the authorization code.
The authorization code provides some important security benefits, such as the ability to authenticate the client, as well as the transmission of the access token directly to the client without passing it through the resource owner’s user-agent and potentially exposing it to others, including the resource owner.
Figure: Authorization code flow
-
Implicit
In the implicit flow, the client is issued an access token directly (as a result of the resource owner authorization). The grant type is implicit, as no intermediate credentials (such as an authorization code) are issued.
Implicit grants improve the responsiveness and efficiency of some clients (such as a client implemented as an in-browser application), since it reduces the number of round trips required to obtain an access token.
Figure: Implicit grant flow
-
Resource owner password credentials
The resource owner’s password credentials (such as username and password) can be used directly as an authorization grant to obtain an access token.
Even though this grant type requires direct client access to the resource owner credentials, the resource owner credentials are used for a single request, and are exchanged for an access token. This grant type can eliminate the need for the client to store the resource owner credentials for future use, by exchanging the credentials with a long-lived access token or refresh token.
Figure: Resource owner password credentials flow
-
Client credentials
The client credentials can be used as an authorization grant when the authorization scope is limited to the protected resources under the control of the client, or to protected resources previously arranged with the authorization server. Client credentials are typically used as an authorization grant when the client is acting on its own behalf (the client is also the resource owner) or is requesting access to protected resources based on an authorization previously arranged with the authorization server.
Figure: Client credentials flow
To request an access token for the implicit, resource owner password credentials, or client credentials grant type, follow the direct access token request instructions.
Prerequisites
To enable your application to use the OAuth 2.0 functionality, follow these steps:
-
To use the Tizen.Account.OAuth2 namespace, the application has to request permission by adding the following privilege to the
tizen-manifest.xml
file:XMLCopy<privileges> <privilege>http://tizen.org/privilege/internet</privilege> </privileges>
-
To use the methods and properties of the Tizen.Account.OAuth2 namespace, include it in your application:
C#Copyusing Tizen.Account.OAuth2;
NoteThe use cases in this guide refer to an
OAuth2Helper
class, which is a user-created class whose purpose is to handle various OAuth2 requests.
Create and manage an OAuth 2.0 request
To make a request with the OAuth 2.0 manager, follow these steps:
-
Create an OAuth2 request:
C#Copyvar request = OAuth2Helper.CreateCodeGrantAuthRequest(true);
-
Set the parameters needed for making the request.
You can set various request properties, such as end points for authentication and token, grant type, client credentials, scopes, authentication scheme, username, and password:
C#Copyinternal const string GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth"; internal const string GOOGLE_TOK_URL = "https://accounts.google.com/o/oauth2/token"; internal const string GOOGLE_REDIRECT_URL = "https://localhost:8080"; internal const string GOOGLE_CLIENT_ID = "12345678901.apps.googleusercontent.com"; internal const string GOOGLE_CLIENT_SECRET = "1ABCD-E2FG3hijkL4MNOp5Qr"; internal const string GOOGLE_SCOPE = "email"; internal const string USER_NAME = "username"; internal const string PASSWORD = "password"; internal static CodeGrantAuthorizationRequest CreateCodeGrantAuthRequest() { return new CodeGrantAuthorizationRequest() { AuthorizationEndpoint = new Uri(GOOGLE_AUTH_URL), RedirectionEndPoint = new Uri(GOOGLE_REDIRECT_URL), TokenEndpoint = new Uri(GOOGLE_TOK_URL), ClientSecrets = new ClientCredentials() { Id = GOOGLE_CLIENT_ID, Secret = GOOGLE_CLIENT_SECRET }, Scopes = new string[] {GOOGLE_SCOPE}, State = "DCEEFWF45453sdffef424" }; } internal static CodeGrantTokenRequest CreateCodeGrantTokenRequest() { return new CodeGrantTokenRequest() { RedirectionEndPoint = new Uri(GOOGLE_REDIRECT_URL), TokenEndpoint = new Uri(GOOGLE_TOK_URL), ClientSecrets = new ClientCredentials() { Id = GOOGLE_CLIENT_ID, Secret = GOOGLE_CLIENT_SECRET }, Scopes = new string[] {GOOGLE_SCOPE}, Code = GOOGLE_AUTH_GRANT_CODE, AuthenticationScheme = AuthenticationScheme.RequestBody, }; }
-
When you no longer need it, free the request by setting it to
null
:C#Copypublic static void Destroy() { request = null; }
Request the server for a grant or token
To obtain the required authorization code or access token, follow these steps:
-
Request the authorization code.
The authorization code grant type is used to obtain both access tokens and refresh tokens. It is a redirection-based flow that requires the client to interact with the server and receive the incoming requests (through redirection) from the authorization server.
To request the authorization code, use the
AuthorizeAsync()
of the Tizen.Account.OAuth2.CodeGrantAuthorizer class:C#Copypublic static async Task AuthorizeAsync_CHECK_EXCEPTION() { /// Precondition /// 1. Valid CodeGrantAuthorizer object /// 2. Prepared CodeGrantAuthorizationRequest parameters var authorizer = new CodeGrantAuthorizer(); Assert.IsNotNull(authorizer, "Object should not be null after construction"); var request = OAuth2Helper.CreateCodeGrantAuthRequest(); Assert.IsNotNull(request, "Object should not be null after construction"); /// Test case try { var response = await authorizer.AuthorizeAsync(request); Assert.IsTrue(false, "Expected to throw an exception"); } catch (Exception ex) { Assert.IsTrue(ex is OAuth2Exception, "Wrong exception thrown. Expected is OAuth2Exception"); } /// Postcondition authorizer.Dispose(); }
-
Request the access token.
Access tokens are credentials used to access protected resources. An access token is a string representing an authorization issued to the client. Tokens represent specific access scopes and durations, granted by the resource owner, and enforced by the resource server and authorization server:
-
Request the access token with the authorization code.
In the authorization code grant type, instead of requesting authorization directly from the resource owner, the client directs the resource owner to an authorization server, which in turn directs the resource owner back to the client with the authorization code.
-
Request the authorization code with the
AuthorizeAsync()
method. The authorization code is returned in a callback. -
Use the authorization code to request the access token by calling the
GetAccessTokenAsync()
method:C#Copypublic static async Task GetAccessTokenAsync_CHECK_EXCEPTION() { /// Precondition /// 1. Valid CodeGrantAuthorizer object /// 2. Prepared CodeGrantTokenRequest parameters var authorizer = new CodeGrantAuthorizer(); Assert.IsNotNull(authorizer, "Object should not be null after construction"); var request = OAuth2Helper.CreateCodeGrantTokenRequest(); Assert.IsNotNull(request, "Object should not be null after construction"); /// Test case try { var response = await authorizer.GetAccessTokenAsync(request); Assert.IsTrue(false, "Expected to throw an exception"); } catch (Exception ex) { Assert.IsTrue(ex is OAuth2Exception, "Wrong exception thrown. Expected is OAuth2Exception"); } /// Postcondition authorizer.Dispose(); }
-
-
Request the access token directly.
You can request an access token in a single step without obtaining the authorization code explicitly. For the authorization code grant type, the code is obtained after the authentication, and passed to the server to obtain the access token internally. For the implicit, resource owner password credentials, and client credentials grant types, you can obtain the access token directly.
To obtain the access token directly, use the
GetAccessTokenAsync()
method. The response from the server is included in a callback:C#Copyinternal static ResourceOwnerPwdCredentialsTokenRequest CreateRoPwdTokenRequest() { return new ResourceOwnerPwdCredentialsTokenRequest() { TokenEndpoint = new Uri(GOOGLE_TOK_URL), ClientSecrets = new ClientCredentials() { Id = GOOGLE_CLIENT_ID, Secret = GOOGLE_CLIENT_SECRET }, AuthenticationScheme = AuthenticationScheme.RequestBody, Username = "user name", Password = "password", RedirectionEndPoint = new Uri(GOOGLE_REDIRECT_URL), State = "state" }; } public static async Task GetAccessTokenAsync_CHECK_EXCEPTION() { /// Precondition /// 1. Valid ResourceOwnerPwdCredentialsAuthorizer object /// 2. Prepared ResourceOwnerPwdCredentialsTokenRequest parameters var authorizer = new ResourceOwnerPwdCredentialsAuthorizer(); Assert.IsNotNull(authorizer, "Object should not be null after construction"); var request = OAuth2Helper.CreateRoPwdTokenRequest(); Assert.IsNotNull(request, "Object should not be null after construction"); /// Test case try { var response = await authorizer.GetAccessTokenAsync(request); Assert.IsTrue(false, "Expected to throw an exception"); } catch (Exception ex) { Assert.IsTrue(ex is OAuth2Exception, "Wrong exception thrown. Expected is OAuth2Exception"); } /// Postcondition authorizer.Dispose(); } internal static ClientCredentialsTokenRequest CreateClientCredsTokenRequest(bool dummy = false) { return new ClientCredentialsTokenRequest() { TokenEndpoint = new Uri(GOOGLE_TOK_URL), RedirectionEndPoint = new Uri(GOOGLE_REDIRECT_URL), AuthenticationScheme = AuthenticationScheme.Basic, ClientSecrets = new ClientCredentials() { Id = GOOGLE_CLIENT_ID, Secret = GOOGLE_CLIENT_SECRET } }; } public static async Task GetAccessTokenAsync_CHECK_EXCEPTION() { /// Precondition /// 1. Valid ClientCredentialsAuthorizer object /// 2. Prepared ClientCredentialsTokenRequest parameters var authorizer = new ClientCredentialsAuthorizer(); Assert.IsNotNull(authorizer, "Object should not be null after construction"); var request = OAuth2Helper.CreateClientCredsTokenRequest(); Assert.IsNotNull(request, "Object should not be null after construction"); /// Test case try { var response = await authorizer.GetAccessTokenAsync(request); Assert.IsTrue(false, "Expected to throw an exception"); } catch (Exception ex) { Assert.IsTrue(ex is OAuth2Exception, "Wrong exception thrown. Expected is OAuth2Exception"); } /// Postcondition authorizer.Dispose(); }
-
-
Refresh the access token.
Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain a new access token when the current access token becomes invalid or expires, or to obtain additional access tokens with an identical or narrower scope.
To refresh an access token, use the
RefreshAccessTokenAsync()
of the Tizen.Account.OAuth2.ClientCredentialsAuthorizer class. The response from the server is included in a callback:C#Copyinternal static RefreshTokenRequest CreateRefreshTokenRequest() { return new RefreshTokenRequest() { TokenEndpoint = new Uri(GOOGLE_REFRESH_TOKEN_URL), ClientSecrets = new ClientCredentials() { Id = GOOGLE_CLIENT_ID, Secret = GOOGLE_CLIENT_SECRET }, AuthenticationScheme = AuthenticationScheme.Basic, RedirectionEndPoint = new Uri(GOOGLE_REDIRECT_URL), RefreshToken = "AQkAQHKoQRyhc7nlxuk4ecr8MC_7kUoBQxCXQ8PpH3u2VNq2KP96UMrCrrav.aO6gHMVhTeeJt_6PVAUqmP5bQSxH8GWp2sO" }; } public static async Task RefreshAccessTokenAsync_CHECK_EXCEPTION() { /// Precondition /// 1. Valid ResourceOwnerPwdCredentialsAuthorizer object /// 2. Prepared ResourceOwnerPwdCredentialsTokenRequest parameters var authorizer = new ResourceOwnerPwdCredentialsAuthorizer(); Assert.IsNotNull(authorizer, "Object should not be null after construction"); var request = OAuth2Helper.CreateRefreshTokenRequest(); Assert.IsNotNull(request, "Object should not be null after construction"); /// Test case try { var response = await authorizer.RefreshAccessTokenAsync(request); Assert.IsTrue(false, "Expected to throw an exception"); } catch (Exception ex) { LogUtils.Write(LogUtils.DEBUG, LogUtils.TAG, ex.ToString()); Assert.IsTrue(true, "Exception should be thrown"); } /// Postcondition authorizer.Dispose(); }
Manage an OAuth 2.0 response
The response from the server is returned as an instance of the Tizen.Account.OAuth2.AuthorizationResponse class, from which various response parameters can be obtained.
To manage the OAuth 2.0 response, follow these steps:
-
Retrieve the response parameters from the response.
You can get various response information, such as the authorization code, state, and custom value:
C#Copypublic static async Task RetrieveResponseInfo() { /// Precondition /// 1. Valid CodeGrantAuthorizer object /// 2. Prepared CodeGrantAuthorizationRequest parameters /// 3. Request for authorization grant string code; string state; var authorizer = new CodeGrantAuthorizer(); var request = OAuth2Helper.CreateCodeGrantAuthRequest(); /// Test case try { var response = await authorizer.AuthorizeAsync(request); Console.WriteLine("Code: {0}", response.Code); Console.WriteLine("State: {0}", response.State); Console.WriteLine("custom data: {0}", response.GetCustomValue("key1")); } catch (Exception ex) { LogUtils.Write(LogUtils.DEBUG, LogUtils.TAG, ex.ToString()); } /// Postcondition authorizer.Dispose(); }
-
Handle response errors.
If the created request is incorrect or required permissions are missing, the server response contains an error. Retrieve the error information from the response to check the issue, using the
Error
property of the created Tizen.Account.OAuth2.OAuth2Exception instance:C#Copypublic static async Task RetrieveServerErrorCode() { /// Precondition /// 1. Valid ResourceOwnerPwdCredentialsAuthorizer object /// 2. Prepared ResourceOwnerPwdCredentialsTokenRequest parameters var authorizer = new ResourceOwnerPwdCredentialsAuthorizer(); var request = OAuth2Helper.CreateRoPwdTokenRequest(); request.Username = "dummy"; /// Test case try { var response = await authorizer.GetAccessTokenAsync(request); } catch (Exception ex) { var exception = ex as OAuth2Exception; var errorResponse = exception.Error; }
-
When you no longer need it, free the response handle with the
Dispose()
method:C#Copy/// Postcondition authorizer.Dispose(); }
Related information
- Dependencies
- Tizen 4.0 and Higher