153

How to add a parameters to the Google OAuth 2.0 redirect_uri?

Just like this:

redirect_uri=http://www.example.com/redirect.html?a=b

The b of a=b is random.

Anyone can help ?

informatik01
  • 16,038
  • 10
  • 74
  • 104
eason
  • 2,854
  • 3
  • 16
  • 18

5 Answers5

289
  1. You cannot add anything to the redirect uri, redirect uri is constant as set in the app settings of Oauth. eg :http://www.example.com/redirect.html

  2. To pass several parameters to your redirect uri, have them stored in state parameter before calling Oauth url, the url after authorization will send the same parameters to your redirect uri as state=THE_STATE_PARAMETERS

So for your case,do this:

/1. create a json string of your parameters ->

{ "a" : "b" , "c" : 1 }

/2. do a base64UrlEncode , to make it URL safe ->

stateString = base64UrlEncode('{ "a" : "b" , "c" : 1 }');

This is a PHP example of base64UrlEncoding & decoding (http://en.wikipedia.org/wiki/Base64#URL_applications) :

function base64UrlEncode($inputStr)
{
    return strtr(base64_encode($inputStr), '+/=', '-_,');
}

function base64UrlDecode($inputStr)
{
    return base64_decode(strtr($inputStr, '-_,', '+/='));
}

So now state would be something like: stateString -> asawerwerwfgsg,

Pass this state in OAuth authorization URL:

https://accounts.google.com/o/oauth2/auth?
  client_id=21302922996.apps.googleusercontent.com&
  redirect_uri=https://www.example.com/back&
  scope=https://www.google.com/m8/feeds/&
  response_type=token&
  state=asdafwswdwefwsdg,

For server side flow it will come along with token : http://www.example.com/redirect.html?token=sdfwerwqerqwer&state=asdafwswdwefwsdg,

For client side flow it will come in the hash along with access token: http://www.example.com/redirect.html#access_token=portyefghsdfgdfgsdgd&state=asdafwswdwefwsdg,

Retrieve the state, base64UrlDecode it, json_decode it, and you have your data.

See more about google OAuth 2 here:

http://code.google.com/apis/accounts/docs/OAuth2.html

Cœur
  • 37,241
  • 25
  • 195
  • 267
DhruvPathak
  • 42,059
  • 16
  • 116
  • 175
  • 1
    base64 is used to obfuscate the data as well as url encode it, if you would need a little bit of extra 'security' through obscurity. – ricosrealm Jun 02 '13 at 02:00
  • @DhruvPathak perfect, I needed to send a custom parameter back with linkedin API redirect and it's same method you described. – ericsicons Jan 25 '15 at 06:48
  • is accessing the query params and token and response data being visible in the url in the first place ok? – Empty Mar 19 '15 at 19:02
  • Phoebe, the token present in the url is not the final access token, it needs to be exchanged for an access token using OAuth apis along with app secret keys. – DhruvPathak Mar 20 '15 at 08:49
  • I tried this suggestion, but for some reason my state always comes back truncated from Google... Any idea why? – Costin_T May 20 '15 at 13:45
  • @SsjCosty same here, and I have no idea how to fix that :|. – Ven Jan 24 '16 at 17:31
  • 20
    The state parameter is used to prevent CSRF attacks during the OAuth flow. You have to set a token in the state parameter when initiating the flow and you should check if you get back the same token in the state parameter when your redirect_uri is hit. Don't do what is done in this answer. A session based solution is probably what you should look at. – Rahim Feb 23 '17 at 07:41
  • 2
    How can I use `state` param to pass several parameters to redirect uri and to prevent `CSRF` attack **at the same time** ? – hellboy Apr 11 '17 at 11:31
  • Hi @DhruvPathak, while setting up the `state` parameter, the value is changed after authentication. Could you please suggest on this – Krishna38 May 07 '18 at 10:47
  • 1
    @hellboy I'm wondering the same thing. Did you manage to add several parameters to the state param (custom values and prevent `CSRF` attacks)? – Kevin Etore May 07 '18 at 21:40
  • Have a look at https://stackoverflow.com/questions/49880144/passing-extra-query-form-parameters-through-spring-social if you work with **Spring Social**! – bgraves Dec 19 '18 at 10:33
  • 1
    In javascript you could use this `state: JSON.stringify({ a: "b", b: "c" }),` on the state attribute – kheengz Mar 08 '21 at 15:12
18

Since the accepted answer does expose the actual data and misuses the state parameter instead of sticking to a nonce to protect against CSRF, I'll try to show a proper method. Rather than passing (read exposing) data it should be kept local. Hydrate it before the request and re-hydrate it after a validated request. "Validated" here means that the state-nonce of request and response match.

You need some kind of temporary client side storage. E.g. for SPA or general websites keep it in state or use the browser's localStorage, a session (or a signed cookie). For mobile apps they should use memory or any other local storage.

Before sending the request generate a nonce (see below) that will be used as state parameter for the request. Store the nonce together with the custom state (e.g. a json) in local storage.

For example, the nonce could be ih4f984hf and the custom state {"role": "customer"}. Then you could store data for re-hydration for that request like this:

"ih4f984hf": {
  "role": "customer"
}

Then use only the nonce as value for the state parameter of the request. (If you absolutely want to combine the nonce and data into the state value be sure to encrypt it and be aware that the length of the value is limited!)

When receiving a response you get the value of the state parameter back. Look it up and if it matches the value in the local storage you may process the data using the stored state. If the nonces do not match the request is potentially from an attacker and should not be processed.

Generating the nonce

Remember that the nature of a nonce is that it is used once only and must be unpredictable! Unpredictable here means ideally random, but practically pseudo-random is ok if the entropry is high enough - in web apps you might want to check Web API Crypto which is supported pretty well.

For further readings this might be helpful:

Community
  • 1
  • 1
Stuck
  • 11,225
  • 11
  • 59
  • 104
  • 1
    But this is optional and Google's documentation doesn't make it sound like you **have** to implement this as an additional security measure. Would you say every app that uses Google oauth2 should implement this? – Florian Walther Aug 20 '22 at 13:29
  • The hole point is that you cannot rely on the parameters of the redirect URL without the nonce. I guess there might be cases where that is irrelevant but normally you should keep data out of the URL. – Stuck Aug 21 '22 at 14:38
  • Do you mean it's dangerous if someone changes the redirect URL manually? Can you give an example? – Florian Walther Aug 21 '22 at 14:48
  • yes, the typical attack vector is a man in the middle attack. But keeping data away from server and network logs is also a good thing. – Stuck Aug 22 '22 at 12:05
  • I'm just trying to understand the problem. Because I put a redirect (relative) URL directly into the state and I don't see how this could be abused. When the authentication flow is over, the user is redirected to this relative URL on my website. They could've also entered this URL themselves. – Florian Walther Aug 23 '22 at 06:21
  • 1
    The oauth website even states: If a client wishes to include request-specific data in the redirect URL, it can instead use the “state” parameter to store data that will be included after the user is redirected. **It can either encode the data in the state parameter itself**, or use the state parameter as a session ID to store the state on the server. Source: https://www.oauth.com/oauth2-servers/redirect-uris/redirect-uri-registration/ To me, that sounds like putting the redirect URL directly into the state. – Florian Walther Aug 23 '22 at 06:28
  • 1
    yes, technically you can put the data there, but from a security and privacy standpoint you must think about which data is fine to expose and what needs to be protected and which attack vectors you application shall mitigate. – Stuck Aug 25 '22 at 09:14
  • Gotcha, thank you for the heads up! – Florian Walther Aug 25 '22 at 13:39
  • The `state` parameter is used to ensure that a request remains unchanged, as CSRF attacks are ONE of the common ways to modify requests. – whc May 03 '23 at 05:49
4

If you are in .NET you could save the parameters in the Session

HttpContext.Current.Session[{varname}]

and redirect to the authorization page without parameters

Response.Redirect(your_uri_approved_with_no_querystring_parameters);
von v.
  • 16,868
  • 4
  • 60
  • 84
rufo
  • 5,158
  • 2
  • 36
  • 47
  • 4
    This does not scale when using a webfarm such as azure. – spender Jan 30 '14 at 16:32
  • 3
    @spender: so you imply that two requests almost in sequence from the same client might be handled by different servers in the webfarm. If that's the case, this is not the only thing affected, basically Session variable couldn't be used in that scenario for anything. BTW: I am not arguing - actually trying to learn here. – rufo Jan 30 '14 at 19:20
  • 8
    It's entirely possible, yes... You can mitigate this by managing session with a session server or backing session off to the database (see http://msdn.microsoft.com/en-us/library/ms178586.aspx), or to enable sticky sessions on your load-balancer to ensure that clients always return to the same webserver node. All of the options I've mentioned are a PITA to set up, so IMO, storing any client state in `Session` should be avoided. – spender Jan 31 '14 at 02:12
4

In Javascript (Node), you could set the state property to an object of key value pairs.

           const oAuth2Client = await new google.auth.OAuth2(
                clientId: <clientId>,
                clientSecret: <clientSecret>,
                redirectUrl: <redirectUrl>,
            );

            return await oAuth2Client.generateAuthUrl({
                access_type: "offline",
                scope: <scopes>,
                state: JSON.stringify({ a: "y", b: "z" }),
            });

On google authorization complete, it returns of the state, code etc from ulr,

const params = JSON.parse(state); // { a: "y", b: "z" }

kheengz
  • 840
  • 12
  • 10
2

You can redirect parameter with url as below,

When you get response from google than you can pass parameter with url,

See below php code for same,

if (isset($_GET['code'])) {
   $client->authenticate();
   $_SESSION['token'] = $client->getAccessToken();
   $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
   header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL) . '?r=page/view');

}

In above example r=page/view is parameter on which i want the response with parameter

Kiran
  • 1,176
  • 2
  • 14
  • 27
  • This is where the state parameter is sent in the google provided PHP code. There are three requests made server side. This means that the final request won't have any query string variables at all. – lol Jan 02 '15 at 15:01
  • works like a charm! I know we can send information in the state param but if application is expecting any value directly as the request param, then it fails. The method you have provided is perfect for this scenario. Thanks! – Jayant Varshney Apr 04 '18 at 13:41