GSignondOauthPlugin

GSignondOauthPlugin — OAuth1/OAuth2 authentication plugin for gSSO single sign-on service

Types and Values

Description

The OAuth plugin provides a client-side implementation of OAuth 1 and OAuth 2 authorization protocols. The overall flow is that the plugin is requested to perform authorization using supplied authorization parameters, and if it has succeeded in doing so, it returns a token string to the application that can be used to access protected resources over https. The plugin is not involved in accessing protected resources, only in initial authorization.

OAuth1 is specified in RFC 5849, OAuth2 is specified in RFC 6749 (with additional info regarding the basic bearer token type in RFC6750). The two versions are not compatible and specify significantly different authorization sequences, for that reason they are implemented as separate mechanisms in the plugin.

The plugin implements the standard GSignondPlugin interface, and after instantiating a plugin object all interactions happen through that interface.

“type” property of the plugin object is set to "oauth".

“mechanisms” property of the plugin object is a list of "oauth1" and "oauth2".

Authorization sequence

The authorization sequence begins with issuing gsignond_plugin_request_initial(). The mechanism parameter should be set to "oauth1" or "oauth2", and the contents of session_data and identity_method_cache parameters depend on the mechanism and are described in detail below.

The plugin responds to the request with one of the following signals:

  • “response-final” This means the authorization sequence ended successfully, and the authorization token is delivered in session_data parameter of the signal. This signal concludes the sequence.

  • “user-action-required” The plugin is requesting to perform a user authorization procedure by opening a webpage in a user-agent (browser) where the user is expected to enter her credentials. Parameters for this step are specified in ui_data . After the user interaction has completed, the results are returned to the plugin with gsignond_plugin_user_action_finished() method, and the authorization process continues.

  • “store” The plugin is requesting to replace the token cache with the contents of identity_method_cache parameter. There is no need to respond to this signal; the authorization process continues immediately.

  • “error” An error has happened in the authorization sequence and it stops. Typical errors are GSIGNOND_ERROR_MISSING_DATA which means there wasn't enough data provided in gsignond_plugin_request_initial() to perform the authorization, GSIGNOND_ERROR_NOT_AUTHORIZED which means the server rejected the authorization attempt, GSIGNOND_ERROR_USER_INTERACTION which means there was an error during interaction with the user.

At any point the application can request to stop the authorization by calling gsignond_plugin_cancel(). The plugin responds with an “error” signal containing a GSIGNOND_ERROR_SESSION_CANCELED error.

Code examples

Example 1. Using OAuth1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* PLEASE NOTE: this example is meant for OAuth plugin developers. If you're
 * an application developer who wants to use this plugin, please refer to
 * libgsignon-glib documentation here:
 * http://accounts-sso.gitlab.io/libgsignon-glib
 */
/*
 * Copyright (C) 2012 Intel Corporation.
 *
 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include <gsignond/gsignond-session-data.h>
#include <gsignond/gsignond-plugin-interface.h>
#include <gsignond/gsignond-error.h>
#include <gsignond/gsignond-utils.h>
#include "gsignond-oauth-plugin.h"

// this function returns a token for the token cache
static GVariant* make_normal_token(void)
{
    GSignondDictionary* token = gsignond_dictionary_new();
    gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
    gsignond_dictionary_set_string(token, "TokenSecret", "megatokensecret");
    gsignond_dictionary_set_string(token, "Realm", "megarealm");
    GVariant* token_var = gsignond_dictionary_to_variant(token);
    g_object_unref(token);
    return token_var;
}

//this function makes a token cache with one unrelated token
//(because it belongs to a different consumer key)
static GSignondDictionary* make_token_cache(void)
{
    GSignondDictionary* tokens = gsignond_dictionary_new();
    gsignond_dictionary_set(tokens, "someotherclient", make_normal_token());
    return tokens;
}

//this callback prints the received token and exits the mainloop
static void response_callback(GSignondPlugin* plugin, GSignondSessionData* result,
                     gpointer user_data)
{
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(result));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Authenticated successfully, got token:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
    g_main_loop_quit(user_data);    
}

//this function prints the content of the updated token cache
static void store_callback(GSignondPlugin* plugin, GSignondSessionData* result,
                     gpointer user_data)
{
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(result));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Should replace the token cache with the following:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
}

//this function shows what the UI interaction component needs to do
static void user_action_required_callback(GSignondPlugin* plugin, 
                                          GSignondSignonuiData* ui_request, 
                                          gpointer user_data)
{
    // ui_request typically contains a URI that needs to be opened, 
    // and a redirect URI that needs to be 'captured' by the user-agent and 
    // reported back to the plugin
    // in practice the ui_request needs to be handed over to a user-agent
    // but here we simply print it    
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(ui_request));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Got a UI interaction request:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
    
    // in practice the following should be received from a user-agent,
    // but in this example for the sake of simplicity we report the hardcoded redirect
    // URI (with additional parameters) immidiately back to the plugin
    GSignondSignonuiData* ui_data = gsignond_signonui_data_new();
    gsignond_signonui_data_set_url_response(ui_data, 
"http://somehost/somegsignondoauthcallback?oauth_token=somerandomtoken&oauth_verifier=somerandomverifier");
    gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_NONE);

    gsignond_plugin_user_action_finished(plugin, ui_data);
    g_object_unref(ui_data);
}

// print an error and exit the mainloop
static void error_callback(GSignondPlugin* plugin, GError* error,
                     gpointer user_data)
{
    g_print("Got an error: %s\n", error->message);
    g_main_loop_quit(user_data);
}


int main (void)
{
#if !GLIB_CHECK_VERSION (2, 36, 0)
    g_type_init ();
#endif

    gpointer plugin = g_object_new(gsignond_oauth_plugin_get_type(), NULL);

    GMainLoop *main_loop = g_main_loop_new (NULL, FALSE);    

    //connect to various signals of the plugin object
    g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), main_loop);
    g_signal_connect(plugin, "user-action-required", 
                     G_CALLBACK(user_action_required_callback), NULL);
    g_signal_connect(plugin, "store", G_CALLBACK(store_callback), NULL);
    g_signal_connect(plugin, "error", G_CALLBACK(error_callback), main_loop);

    GSignondSessionData* data = gsignond_session_data_new();
    GSignondDictionary* token_cache = make_token_cache();

    //fill in necessary data for OAuth1 authorization
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "ConsumerKey", "megaclient");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "ConsumerSecret", "megasecret");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "Realm", "megarealm");
    gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
    
    const gchar *realm_list[] = { "somehost", NULL };
    GSequence *allowed_realms = gsignond_copy_array_to_sequence(realm_list);
    gsignond_session_data_set_allowed_realms(data, allowed_realms);
    g_sequence_free(allowed_realms);
    
    // can also be HMAC-SHA1, or RSA-SHA1 (in the latter case, also RSAPrivateKey
    // needs to be set
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "SignatureMethod", "PLAINTEXT");
    
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "RequestEndpoint", "https://somehost/temporarytokenpath");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "AuthorizationEndpoint", "https://somehost/authorization");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "Callback", "http://somehost/somegsignondoauthcallback");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "TokenEndpoint", "https://somehost/accesstokenpath");
 
    //start the authorization and run the mainloop
    //any further processing happens in signal callbacks
    gsignond_plugin_request_initial(plugin, data, token_cache, "oauth1");
    g_object_unref(data);
    g_object_unref(token_cache);
    
    g_main_loop_run (main_loop);
    
    g_object_unref(plugin);
    g_main_loop_unref(main_loop);
    
    return 0;
}

Example 2. Using OAuth2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* PLEASE NOTE: this example is meant for OAuth plugin developers. If you're
 * an application developer who wants to use this plugin, please refer to
 * libgsignon-glib documentation here:
 * http://accounts-sso.gitlab.io/libgsignon-glib
 */
/*
 * Copyright (C) 2012 Intel Corporation.
 *
 * Contact: Alexander Kanavin <alex.kanavin@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include <gsignond/gsignond-session-data.h>
#include <gsignond/gsignond-plugin-interface.h>
#include <gsignond/gsignond-error.h>
#include <gsignond/gsignond-utils.h>
#include "gsignond-oauth-plugin.h"


// this function returns a token for the token cache
static GVariant* make_normal_token()
{
    GSignondDictionary* token = gsignond_dictionary_new();
    gsignond_dictionary_set_string(token, "AccessToken", "megaaccesstoken");
    GDateTime* now = g_date_time_new_now_utc();
    gsignond_dictionary_set_int64(token, "Timestamp", 
        g_date_time_to_unix(now));
    g_date_time_unref(now);
    gsignond_dictionary_set_int64(token, "ExpiresIn", 3600);
    gsignond_dictionary_set_string(token, "RefreshToken", "megarefreshtoken");
    gsignond_dictionary_set_string(token, "Scope", "somescope1 somescope2 somescope3");
    GVariant* token_var = gsignond_dictionary_to_variant(token);
    g_object_unref(token);
    return token_var;
}

//this function makes a token cache with one unrelated token
//(because it belongs to a different client id)
static GSignondDictionary* make_token_cache()
{
    GSignondDictionary* tokens = gsignond_dictionary_new();
    GSignondDictionary* client_tokens = gsignond_dictionary_new();
    gsignond_dictionary_set(client_tokens, "somescope1 somescope2 somescope3", make_normal_token());
    gsignond_dictionary_set(tokens, "someotherclient", gsignond_dictionary_to_variant(client_tokens));
    g_object_unref(client_tokens);
    return tokens;
}

//this callback prints the received token and exits the mainloop
static void response_callback(GSignondPlugin* plugin, GSignondSessionData* result,
                     gpointer user_data)
{
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(result));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Authenticated successfully, got token:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
    g_main_loop_quit(user_data);    
}

//this function prints the content of the updated token cache
static void store_callback(GSignondPlugin* plugin, GSignondSessionData* result,
                     gpointer user_data)
{
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(result));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Should replace the token cache with the following:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
}

//this function shows what the UI interaction component needs to do
static void user_action_required_callback(GSignondPlugin* plugin, 
                                          GSignondSignonuiData* ui_request, 
                                          gpointer user_data)
{
    // ui_request typically contains a URI that needs to be opened, 
    // and a redirect URI that needs to be 'captured' by the user-agent and 
    // reported back to the plugin
    // in practice the ui_request needs to be handed over to a user-agent
    // but here we simply print it
    GVariant* token_variant = gsignond_dictionary_to_variant(GSIGNOND_DICTIONARY(ui_request));
    gchar* token_str = g_variant_print(token_variant, TRUE);
    g_print("Got a UI interaction request:\n%s\n",
             token_str);
    g_free(token_str);
    g_variant_unref(token_variant);
    
    // in practice the following should be received from a user-agent,
    // but in this example for the sake of simplicity we report the hardcoded redirect
    // URI (with additional parameters) immidiately back to the plugin
    GSignondSignonuiData* ui_data = gsignond_signonui_data_new();
    gsignond_signonui_data_set_url_response(ui_data, 
"http://somehost/login.html?state=somerandomstate&code=somerandomcode");
    gsignond_signonui_data_set_query_error(ui_data, SIGNONUI_ERROR_NONE);

    gsignond_plugin_user_action_finished(plugin, ui_data);
    g_object_unref(ui_data);
}

// print an error and exit the mainloop
static void error_callback(GSignondPlugin* plugin, GError* error,
                     gpointer user_data)
{
    g_print("Got an error: %s\n", error->message);
    g_main_loop_quit(user_data);
}

int main (void)
{
#if !GLIB_CHECK_VERSION (2, 36, 0)
    g_type_init ();
#endif

    gpointer plugin = g_object_new(gsignond_oauth_plugin_get_type(), NULL);

    GMainLoop *main_loop = g_main_loop_new (NULL, FALSE);    

    //connect to various signals of the plugin object
    g_signal_connect(plugin, "response-final", G_CALLBACK(response_callback), main_loop);
    g_signal_connect(plugin, "user-action-required", 
                     G_CALLBACK(user_action_required_callback), NULL);
    g_signal_connect(plugin, "store", G_CALLBACK(store_callback), NULL);
    g_signal_connect(plugin, "error", G_CALLBACK(error_callback), main_loop);

    GSignondSessionData* data = gsignond_session_data_new();
    GSignondDictionary* token_cache = make_token_cache();

    //fill in necessary data for OAuth2 authorization
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "ClientId", "megaclient");
    gsignond_session_data_set_ui_policy(data, GSIGNOND_UI_POLICY_DEFAULT);
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "TokenHost", "somehost");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "TokenPath", "/tokenpath");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "Scope", "Photos Videos");
    
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "AuthHost", "somehost");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "AuthPath", "/somepath");
    
    const gchar *realm_list[] = { "somehost", NULL };
    GSequence *allowed_realms = gsignond_copy_array_to_sequence(realm_list);
    gsignond_session_data_set_allowed_realms(data, allowed_realms);
    g_sequence_free(allowed_realms);
    
    //use authorization code grant for this example as it's the most complex
    //of those provided in OAuth2 spec
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "ResponseType", "code");
    gsignond_dictionary_set_string(GSIGNOND_DICTIONARY(data), "RedirectUri", "http://somehost/login.html");

    //start the authorization and run the mainloop
    //any further processing happens in signal callbacks
    gsignond_plugin_request_initial(plugin, data, token_cache, "oauth2");
    g_object_unref(data);
    g_object_unref(token_cache);
    
    g_main_loop_run (main_loop);
    
    g_object_unref(plugin);
    g_main_loop_unref(main_loop);
    
    return 0;
}

HTTP-related parameters in requests

Both OAuth1 and OAuth2 are using HTTP requests for authorization. It's possible to use the following entries in gsignond_plugin_request_initial() session_data parameter to influence those requests:

  • gsignond_session_data_set_network_proxy() provides a HTTP proxy to use. If this parameter is not set, the system proxy configuration is used.

  • "SslStrict" key whose value is a gboolean. If set to FALSE, then server certificates which are invalid (for example, expired, or self-signed) will not be rejected. If set to TRUE or not set, then server certificates have to be valid.

OAuth version 1 parameters for authorization

Where not specified otherwise, parameters are strings.

Parameters in gsignond_plugin_request_initial() identity_method_cache

This parameter contains a cache of previously received tokens in the form of a GSignondDictionary. Tokens are indexed by a ConsumerKey in the dictionary, and each token is itself a GSignondDictionary, with keys and values described below in the token format section.


Parameters in gsignond_plugin_request_initial() session_data

  • "ConsumerKey" (mandatory) - the identifier portion of the client credentials (equivalent to a username). Refer to RFC5849 section 3.1

  • gsignond_session_data_set_ui_policy() (mandatory) - if set to GSIGNOND_UI_POLICY_DEFAULT a default authorization sequence is used, which may involve re-using a previously cached token without making any authorization server requests at all. If set to GSIGNOND_UI_POLICY_REQUEST_PASSWORD any cached token corresponding to the ConsumerKey is discarded and the authorization procedure is started from the beginning.

  • gsignond_session_data_set_allowed_realms (mandatory) - a list of domains that RequestEndpoint, AuthorizationEndpoint and TokenEndpoint hosts must be in. There authorization sequence will fail if any of the endpoints is not in this list.

  • "Realm" (optional) - a requested realm for the token, as specified in

    RFC5849 section 3.5.1.
  • "RequestEndpoint" (mandatory) - a URL that specifies an endpoint used by the plugin to obtain a set of temporary credentials, as specified in

    RFC5849 section 2.

    The endpoint must use HTTPS scheme.

  • "Callback" (mandatory) - a callback URI where the user is redirected after completing the Resource Owner Authorization step, as specified in

    RFC5849 section 2.
  • "SignatureMethod" (mandatory) - one of "PLAINTEXT", "HMAC-SHA1", or "RSA-SHA1" - a method used used by the plugin to sign the requests. Specified in RFC5849 section 3.4.

  • "ConsumerSecret" (optional) - the shared secret portion of the client credentials, used to sign requests to the server when using PLAINTEXT or HMAC-SHA1 signature methods. An empty consumer secret is used if it's not supplied.

  • "RSAPrivateKey" (mandatory, if RSA-SHA1 signature method is used) - PEM formatted X.509 private key, used to sign requests to the server when using RSA-SHA1 signature methods.

  • "AuthorizationEndpoint" (mandatory) - Resource Owner Authorization endpoint, to which the user (resource owner) is redirected to grant authorization, as specified in

    RFC5849 section 2.
  • gsignond_session_data_set_username() and gsignond_session_data_set_secret() (optional) - these two parameters may be used when opening the authorization endpoint URI to initialize corresponding fields on the webpage.

  • "TokenEndpoint" (mandatory) - a URL that specifies an endpoint used by the plugin to obtain a set of access credentials, as specified in

    RFC5849 section 2.

Parameters for “user-action-required” signal issued by plugin

  • gsignond_signonui_data_set_open_url() (mandatory) - a URI that should be opened in a user-agent (browser) for the user (resource owner) to authenticate herself. This URI is taken from "AuthorizationEndpoint" parameter of gsignond_plugin_request_initial() and additional parameters may be appended to the query component.

  • gsignond_signonui_data_set_final_url() (mandatory) - a URI where the user-agent should be redirected after a successfull authentication by the resource owner. This expected URI is taken from the "Callback" parameter of gsignond_plugin_request_initial() call to the plugin.The actual (vs. expected) URI may contain additional parameters in the query component of the URI that are used to continue the authorization process.

  • gsignond_signonui_data_set_username() and gsignond_signonui_data_set_password() (optional) - these two parameters may be used when opening the URI to initialize corresponding fields on the webpage.


Parameters in gsignond_plugin_user_action_finished() ui_data

  • gsignond_signonui_data_set_query_error() (mandatory) - indicates if there was an error in UI interaction and what it was. May be SIGNONUI_ERROR_NONE (which means no error), SIGNONUI_ERROR_CANCELED or any other error.

  • gsignond_signonui_data_get_url_response() (mandatory) - the URI that the user-agent was redirected to. The callback URI supplied in parameters of gsignond_plugin_request_initial() must be a prefix of this URI. The URI also has to contain parameters in the query component that are necessary to continue the authorization sequence.


Token and its parameters in “response-final” signal

gsignond_plugin_response_final() signal concludes the authorization process and returns a GSignondDictionary parameter that contains the access token and some token parameters:

  • "AccessToken" (mandatory) - the token itself

  • "TokenSecret" (mandatory) - the token shared-secret, used by the application to sign requests for protected resources

  • "Realm" (optional) - the token realm, as specified in

    RFC5849 section 3.5.1.
  • "ExtraFields" (mandatory) - a GSignondDictionary containing any additional parameters returned by the server together with the access token. This dictionary may be empty, or if it's not, it typically contains service-specific, non-standardized keys and values. This replaces the now deprecated "TokenParameters" parameter.

OAuth version 2 parameters for authorization

Where not specified otherwise, parameters are strings.


Parameters in gsignond_plugin_request_initial() identity_method_cache

This parameter contains a cache of previously received tokens in the form of a GSignondDictionary. The keys are tokens' ClientId and values are also GSignondDictionary. Those second-level dictionaries contain token scopes as keys and tokens as values. This two-level approach is done to allow caching several tokens with unrelated scopes per client.

Finally, each token is itself a GSignondDictionary, with keys and values described below in the token format section.


Parameters in gsignond_plugin_request_initial() session_data

  • "ClientId" (mandatory) - client identifier as described in

    RFC6749 section 2.2.
  • "ClientSecret" (optional) - client password as described in

    RFC6749 section 2.3.
  • gsignond_session_data_set_ui_policy() (mandatory) - if set to GSIGNOND_UI_POLICY_DEFAULT a default authorization sequence is used, which may involve re-using a previously cached token without making any authorization server requests at all. If set to GSIGNOND_UI_POLICY_REQUEST_PASSWORD any cached token information (including a refresh token) corresponding to the ClientId is discarded and the authorization procedure is started from the beginning.

  • gsignond_session_data_set_allowed_realms (mandatory) - a list of domains that AuthHost and TokenHost must be in. The authorization sequence will fail if either of the hosts is not in this list.

  • "Scope" (optional) - a space-separated list of scopes that are requested for the token, as specified in

    RFC6749 section 3.3.
  • "ForceClientAuthViaRequestBody" (optional) - by default the clients are authenticated via HTTP Basic authorization mechanism, as described in

    RFC6749 section 2.3.1.

    The RFC stipulates that all OAuth 2 servers must support this, however, it was discovered that at least Google and Facebook require client authorization in the request body (which is, according to standard, optional and not recommended). If set to TRUE, this parameter forces this non-compliant client authorization to be used.

  • "ForceTokenRefresh" (optional) - normally if the token cache contains a suitable token, it is returned immediately. If this parameter is set to TRUE, then a refresh token is always used instead to obtain a new token.

Parameters used for authorization code grant or implicit grant flows

  • "ResponseType" (mandatory) - should be set to "code" or "token" as described in

    RFC6749 section 3.1.1.
  • "AuthHost" (mandatory) - hostname component of the authorization endpoint URI, as described in

    RFC6749 section 3.1.

    If it is the equal as "TokenHost", a single "Host" parameter is also possible.

  • "AuthPath" (mandatory) - pathname component of the authorization endpoint URI, as described in

    RFC6749 section 3.1.
  • "AuthPort" (optional) - port component of the authorization endpoint URI, as described in

    RFC6749 section 3.1.

    If not specified, standard https port is used.

  • "AuthQuery" (optional) - query component of the authorization endpoint URI, as described in

    RFC6749 section 3.1.

    This can be used to add provider-specific parameters to the authorization URI. One such parameter is Google's "login_hint" that allows the authorization endpoint pre-fill the login box, or select the proper multi-login session. It is specified at

    https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl. Another

    custom parameter is Facebook's "display", specified at

    https://developers.facebook.com/docs/reference/dialogs/oauth/,

    that affects the way the authorization page looks. Typical values are "page", "popup" and "touch".

  • "RedirectUri" (optional) - redirection endpoint as described in

    RFC6749 section 3.1.2.
  • gsignond_session_data_set_username() and gsignond_session_data_set_secret() (optional) - these two parameters may be used by UI implementation to initialize corresponding fields on the webpage when opening the authorization endpoint URI.

Parameters used for resource owner password credentials grant flow

Refer to RFC6749 section 4.3.

  • "GrantType" (mandatory) - must be set to "password"

  • gsignond_session_data_set_username() and gsignond_session_data_set_secret() (mandatory) - resource owner username and password

Parameters used for client credentials grant flow

Refer to RFC6749 section 4.4.

  • "GrantType" (mandatory) - must be set to "client_credentials"

Parameters used for authorization code, resource owner password or client credentials grant flows (but not implicit grant flow)

  • "TokenHost" (mandatory) - hostname component of the token endpoint URI, as described in

    RFC6749 section 3.2.

    If it is the equal as "AuthHost", a single "Host" parameter is also possible.

  • "TokenPath" (mandatory) - pathname component of the token endpoint URI, as described in

    RFC6749 section 3.2.
  • "TokenPort" (optional) - port component of the token endpoint URI, as described in

    RFC6749 section 3.2.

    If not specified, standard https port is used.

  • "TokenQuery" (optional) - query component of the token endpoint URI, as described in

    RFC6749 section 3.2.

Parameters for “user-action-required” signal issued by plugin

This signal is issued only when using authorization code grant or implicit code grant flows, and contains the following parameters:

  • gsignond_signonui_data_set_open_url() (mandatory) - an authorization endpoint URI that should be opened in a user-agent (browser) for the user (resource owner) to authenticate herself. This URI is constructed using parameters of gsignond_plugin_request_initial() and additional parameters may be appended to the query component.

  • gsignond_signonui_data_set_final_url() (optional) - a redirection endpoint URI where the user-agent should be redirected after authentication by the resource owner has finished. This expected URI is taken from the "RedirectUri" parameter of gsignond_plugin_request_initial() call to the plugin. The actual (vs. expected) URI may contain additional parameters in the query or fragment components of the URI that are used to determine the outcome of the authorization process.

  • gsignond_signonui_data_set_username() and gsignond_signonui_data_set_password() (optional) - these two parameters may be used when opening the authorization endpoint URI to initialize corresponding fields on the webpage.


Parameters in gsignond_plugin_user_action_finished() ui_data

This function is called when UI interaction has completed and only when using authorization code grant or implicit code grant flows.

  • gsignond_signonui_data_set_query_error() (mandatory) - indicates if there was an error in UI interaction and what it was. May be SIGNONUI_ERROR_NONE (which means no error), SIGNONUI_ERROR_CANCELED or any other error.

  • gsignond_signonui_data_get_url_response() (mandatory) - the URI that the user-agent was redirected to. The redirection endpoint URI supplied in parameters of gsignond_plugin_request_initial() must be a prefix of this URI. The URI also has to contain parameters in the query component (if using authorization code grant) or in the fragment component (if using implicit code grant) that are necessary to continue the authorization sequence. Specific information is provided at

    RFC6749 section 4.1.2

    and RFC6749 section 4.2.2 respectively.


Token and its parameters in “response-final” signal

gsignond_plugin_response_final() signal concludes the authorization process and returns a GSignondDictionary parameter that contains the access token and some token parameters:

  • "AccessToken" (mandatory) - the token itself

  • "TokenType" (mandatory) - the token type, as specified in

    RFC6749 section 7.1.

    Currently only one token type is supported (the bearer token, standardizied in

    RFC6750).
  • "ExtraFields" (mandatory) - a GSignondDictionary containing any additional parameters returned by the server together with the access token. The contents of this parameter is specific to the token type, and for bearer tokens it's empty. This replaces the now deprecated "TokenParameters" parameter.

  • "Scope" (optional) - the scopes of the issued token, a space separated list as specified in

    RFC6749 section 3.3.
  • "Timestamp" (mandatory) - a gint64 Unix time specifying the time when token was issued. A Unix time is the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC.

  • "ExpiresIn" (optional) - the lifetime in seconds of the access token. If specified, the token will expire at Timestamp+ExpiresIn point in time.

  • "Duration" (optional) - deprecated, replaced by "ExpiresIn" above.

  • "RefreshToken" (optional) - refresh token as specified in

    RFC6749 section 6.

Plugin API common to OAuth1 and Oauth2


Parameters of “store” signal

This signal is issued by the plugin when the token cache needs to be updated. The parameter is a GSignondDictionary of tokens. The specific cache format is same as identity_method_cache parameter of gsignond_plugin_request_initial() and is desribed in detail in corresponding OAuth1 and OAuth2 sections.

The token cache should be entirely replaced with the parameter of the signal; the plugin preserves existing tokens that were supplied to gsignond_plugin_request_initial() in identity_method_cache parameter.


Errors issued via “error” signal

At any point in the authorization process the plugin may issue this signal with an error parameter that is a GError. The error has domain field set to GSIGNOND_ERROR. code field can be one of GSIGNOND_ERROR_MISSING_DATA (not enough data was supplied in gsignond_plugin_request_initial()), GSIGNOND_ERROR_NOT_AUTHORIZED (there was an error in the authorization process), GSIGNOND_ERROR_USER_INTERACTION (there was an error in the interaction with the user), GSIGNOND_ERROR_SESSION_CANCELED (the authorization process was canceled). message field tells additional details about the exact cause of the error, and it's intended to help programming and debugging, but not meant to be understood by end users directly (although it can be shown to them).

Functions

Types and Values

struct GSignondOauthPlugin

struct GSignondOauthPlugin {
    GObject parent_instance;
    
    GSignondSessionData* oauth2_request;
    GSignondSessionData* oauth1_request;
    GSignondDictionary* token_cache;
    SoupSession* soup_session;
};

Opaque structure for the OAuth plugin object


struct GSignondOauthPluginClass

struct GSignondOauthPluginClass {
};

Opaque structure for the OAuth plugin class

See Also

GSignondPlugin