Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Oauth2 with .NET
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  21 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Caroline McLean  
View profile  
 More options May 14 2012, 10:52 am
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Mon, 14 May 2012 07:52:25 -0700 (PDT)
Local: Mon, May 14 2012 10:52 am
Subject: Oauth2 with .NET

Danny,

In our last biweekly meeting, you recommended everyone use OAuth 2.0

As described in "Using OAuth 2.0 for Server to Server Applications" (
https://developers.google.com/accounts/docs/OAuth2ServiceAccount) " The
mechanics of this interaction require applications to create and
cryptographically sign JWTs. Developers are strongly encouraged to use an
existing library to perform these tasks."

However, there is currently no support for this in .NET?  Is there an ETA
on the Crypto support in the .NET library? Is there a recommended
alternative or is it best to wait until this support is present.

Thanks,
Caroline


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 14 2012, 11:28 am
From: Daniel Hermes <dher...@google.com>
Date: Mon, 14 May 2012 08:28:48 -0700
Local: Mon, May 14 2012 11:28 am
Subject: Re: Oauth2 with .NET

Caroline,

There is support for it and I'll be posting in depth instructions hopefully
sometime this week.

In the meantime, check out the oauth2_sample:
http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/...

On Mon, May 14, 2012 at 7:52 AM, Caroline McLean <bbmcarol...@gmail.com>wrote:

--
Daniel Hermes | Developer Programs Engineer | dher...@google.com | (504)
5DJ-GOOG

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 14 2012, 5:00 pm
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Mon, 14 May 2012 14:00:17 -0700 (PDT)
Local: Mon, May 14 2012 5:00 pm
Subject: Re: Oauth2 with .NET

Thanks Danny!


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 15 2012, 1:24 pm
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Tue, 15 May 2012 10:24:18 -0700 (PDT)
Local: Tues, May 15 2012 1:24 pm
Subject: Re: Oauth2 with .NET

Looks like the sample you referenced, addresses the installed Applications
OAuth requirements.  I need support for the server to server Oauth as
described in my first message.  The challenge being generating a JSON Web
Token and appropriately signing it with the private key generated by
Google.  "When at all possible, a developer should not write the logic for
creating and signing JWTs." However it does not list a .net library on that
page. Is JWT support included in the current .net library?

Thanks,
Caroline


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 15 2012, 4:02 pm
From: Daniel Hermes <dher...@google.com>
Date: Tue, 15 May 2012 13:02:31 -0700
Local: Tues, May 15 2012 4:02 pm
Subject: Re: Oauth2 with .NET

Caroline,

Sorry I missed that. I'll check with the developers of the library to see
if there is a timeline.

Regards,

On Tue, May 15, 2012 at 10:24 AM, Caroline McLean <bbmcarol...@gmail.com>wrote:

--
Daniel Hermes | Developer Programs Engineer | dher...@google.com | (504)
5DJ-GOOG

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 15 2012, 6:41 pm
From: Daniel Hermes <dher...@google.com>
Date: Tue, 15 May 2012 15:41:27 -0700
Local: Tues, May 15 2012 6:41 pm
Subject: Re: Oauth2 with .NET

Caroline,

I just spoke with the maintainers and there are no plans to support this in
the library due to constraints of time.

Is there a particular reason you needed this with service accounts? You
should be able to accomplish just about anything you need with the standard
OAuth2 flow.

Regards,

--
Daniel Hermes | Developer Programs Engineer | dher...@google.com | (504)
5DJ-GOOG

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 15 2012, 6:54 pm
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Tue, 15 May 2012 15:54:28 -0700 (PDT)
Local: Tues, May 15 2012 6:54 pm
Subject: Re: Oauth2 with .NET

Hmm, maybe I am confused, it looked like the other Oauth2 flows required
manual intervention to obtain the token, IE a physical user to hit the
approve button, we are doing automated product feeds, through our web
applications, that are not run with a user in the flow.  Did I confuse
something?  The web server (vs the server to server Oauth) states the
following: " The response will be sent to the redirect_uri as specified in
an access token request. If the user approves the access request, then the
response contains an authorization code and the state parameter (if
included in the request). If the user does not approve the request the
response contains an error message. All responses are returned to the web
server on the query string, as shown below:"

Thanks again for your help.
Caroline


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 15 2012, 7:07 pm
From: Daniel Hermes <dher...@google.com>
Date: Tue, 15 May 2012 16:07:32 -0700
Local: Tues, May 15 2012 7:07 pm
Subject: Re: Oauth2 with .NET

Caroline,

You will only need your users to "manually intervene" to accept the token
once. You can set the redirect uri to a page in your "web application" and
parse the returned code from there. (This is the parameters.AccessCode =
line in the sample).
[Sample:
http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/...
]

Once you obtain an access token and refresh token, you can use the access
token to sign requests until it expires (3600 second expiry usually). After
it expires, you can use the refresh token to get a new access token without
user intervention.

You don't have to worry about any of the refresh logic because the library
handles all of it.

So it's enough to serialize the data in an OAuth2Parameters object somehow
and keep it around for your user after the initial acceptance:
http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/...

Check out the OAuth2 docs for more info:
https://developers.google.com/accounts/docs/OAuth2

On Tue, May 15, 2012 at 3:54 PM, Caroline McLean <bbmcarol...@gmail.com>wrote:

--
Daniel Hermes | Developer Programs Engineer | dher...@google.com | (504)
5DJ-GOOG

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 16 2012, 10:24 am
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Wed, 16 May 2012 07:24:26 -0700 (PDT)
Local: Wed, May 16 2012 10:24 am
Subject: Re: Oauth2 with .NET

The service to service approach for us is probably most appropriate. The
less we need our merchants to do the better.  I think I am almost there.  I
set up the google service account and think I have the JWT generated and
signed appropriately, but I am receiving "invalid_grant" back.  I have
verified I am using the correct email account in the payload (xxx
@developer.gserviceaccount.com), is there someone that can look at the logs
and give me more detail as to what exactly is failing. I know its by design
that little info is returned.

Thanks,
Caroline


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 16 2012, 10:38 am
From: Daniel Hermes <dher...@google.com>
Date: Wed, 16 May 2012 14:38:23 +0000
Local: Wed, May 16 2012 10:38 am
Subject: Re: Oauth2 with .NET

In response to "The less we need our merchants to do the better.":

As I said, the OAuth2 flow will only need user intervention for the very
first step. No matter how you slice it, you'll need their consent one way
another. Using a page on your site as your redirect uri, you will be able
to set up the OAuth2 flow completely on your site without having to write
any extra hacks.

On Wed, May 16, 2012 at 2:24 PM, Caroline McLean <bbmcarol...@gmail.com>wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 17 2012, 9:23 am
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Thu, 17 May 2012 06:23:00 -0700 (PDT)
Subject: Re: Oauth2 with .NET

Danny, I switched over to use the Oauth2 for web server applications.
 Using the sample app, I was able to receive a token and it works great to
query the shopping api (after adding
https://www.googleapis.com/auth/structuredcontent to the scope).  However
the refresh token comes back null, so when my hour is up, I have nothing.
 Here is the code from the sample app:

              OAuth2Parameters parameters = new OAuth2Parameters() {
                    ClientId = clientId,
                    ClientSecret = clientSecret,
                    RedirectUri = redirectUri,
                    Scope = scopes
                };

                string url =
OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
                Console.WriteLine("Authorize URI: " + url);
                parameters.AccessCode = Console.ReadLine();

                OAuthUtil.GetAccessToken(parameters);

Looking at the parameters object in the debugger, the RefreshToken in null
(AccessType is "offline")  Is there a bug in the .net client or am I doing
something wrong?

Thanks,
Caroline

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 17 2012, 10:23 am
From: Daniel Hermes <dher...@google.com>
Date: Thu, 17 May 2012 07:23:05 -0700
Local: Thurs, May 17 2012 10:23 am
Subject: Re: Oauth2 with .NET

Caroline,

This part confused the heck out of me when I first started using OAuth.

I wrote a really long StackOverflow post [1] about this for the Python
side, but most of it just applies to the OAuth2 flow:

In particular, my Future Note 3 is helpful here:
"Also, if you lose your refresh token and would like to get another one
without having to go to the browser to revoke [2] the original, you can use
the approval_prompt parameter to get a new refresh token"

From another Google page [3] which I wouldn't have expected you to find:
"If your repeat this process, you will not see the consent screen. Google
remembers your consent, and simply issues a new access token to the site.
If, for some reason, you'd like to reprompt the user for consent, you can
add approval_prompt=force to the parameters in the request."

Most importantly, if you have already given consent, subsequent times
through the process you will just be issued a new access token. To get a
refresh token, you either need to revoke [2] the token or include
approval_prompt=force in the request query parameters (can be done in .NET
with ApprovalPrompt = "force"). By default approval_prompt is set to auto.

Other reference:
https://groups.google.com/forum/#!topic/oauth2-dev/6lvmvoht0xI

Regards,

[1]
http://stackoverflow.com/questions/5903278/gdata-python-api-analytics...
[2] https://accounts.google.com/IssuedAuthSubTokens
[3] https://developers.google.com/accounts/docs/OAuth2Login#simpleexample

On Thu, May 17, 2012 at 6:23 AM, Caroline McLean <bbmcarol...@gmail.com>wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 17 2012, 10:34 am
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Thu, 17 May 2012 07:34:00 -0700 (PDT)
Subject: Re: Oauth2 with .NET

Awesome thanks, that did the trick!...Of course I need to wait an hour to
make sure the refresh token works ;)

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 17 2012, 10:36 am
From: Daniel Hermes <dher...@google.com>
Date: Thu, 17 May 2012 07:36:35 -0700
Local: Thurs, May 17 2012 10:36 am
Subject: Re: Oauth2 with .NET

No. You can set the access_token to something silly and use the refresh
token right away.

On Thu, May 17, 2012 at 7:34 AM, Caroline McLean <bbmcarol...@gmail.com>wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 17 2012, 11:31 am
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Thu, 17 May 2012 08:31:27 -0700 (PDT)
Local: Thurs, May 17 2012 11:31 am
Subject: Re: Oauth2 with .NET

hmm, I literally appended silly to my auth token and received an exception
on the service.query call
Token invalid - Invalid token: Invalid stateless token:
ya29.AHES6ZQYtvTknx1HxOhBLe2dDKXypKXXXXXXXXXXXXXXXXXXsilly 3 - Error 401

My code is as follows (do I have to catch the exception and manually call a
refresh token?):

            OAuth2Parameters parameters = new OAuth2Parameters();
            parameters.AccessToken = authToken;
            parameters.RefreshToken = refreshToken;

            GOAuth2RequestFactory requestFactory = new
GOAuth2RequestFactory("apps", "UniteU", parameters);
            service.RequestFactory = requestFactory;

            // Retrieve the list of all existing products
            string projection = "schema";
            ProductQuery query = new ProductQuery(projection, accountId);
            ProductFeed feed = service.Query(query);

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 17 2012, 1:38 pm
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Thu, 17 May 2012 10:38:02 -0700 (PDT)
Local: Thurs, May 17 2012 1:38 pm
Subject: Re: Oauth2 with .NET

I got the same response, restoring the token to its original value once the
hour had passed, I must be missing one more thing :)

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile  
 More options May 17 2012, 2:19 pm
From: Daniel Hermes <dher...@google.com>
Date: Thu, 17 May 2012 11:19:22 -0700
Local: Thurs, May 17 2012 2:19 pm
Subject: Re: Oauth2 with .NET

Use "structuredcontent" rather than "apps" as the service name.

Here is code I have written that works:
*OAuth2Parameters parameters = new OAuth2Parameters() {*
*    ClientId = clientId,*
*    ClientSecret = clientSecret,*
*    RedirectUri = redirectUri,*
*    Scope = scope,*
*    ApprovalPrompt = "force" // Forcing approval for a refresh token*
*};*
*
*
*string authorizeUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);*
*Console.WriteLine("Please visit: {0}", authorizeUrl);*
*
*
*Console.WriteLine("Please enter the redirected url:");*
*string redirectUrl = Console.ReadLine();*
*Uri uri = new Uri(redirectUrl);*
*OAuthUtil.GetAccessToken(uri.Query, parameters);*
*
*
*string accountId = "XXXXXX";  // Your account ID here*
*string userAgent = "content-api-example"; // WHATEVER YOU LIKE*
*ContentForShoppingService service = new ContentForShoppingService(*
*    userAgent, accountId);*
*
*
*string serviceName = "structuredcontent";*
*
*
*GOAuth2RequestFactory requestFactory = new
GOAuth2RequestFactory(serviceName,*
*                                                                 userAgent,
*
*
 parameters);*
*service.RequestFactory = requestFactory;*
*
*
*int maxResults = 1;*
*ProductQuery query = new ProductQuery();*
*query.NumberToRetrieve = maxResults;*
*ProductFeed itemsFeed = service.Query(query);*
*
*
*Console.WriteLine("Before Refresh:");*
*Console.WriteLine("AccessToken: {0}", parameters.AccessToken);*
*Console.WriteLine("RefreshToken: {0}", parameters.RefreshToken);*
*parameters.AccessToken = "ANY-BAD-STRING-YOU-LIKE";*
*
*
*query.StartToken = itemsFeed.StartToken; // Using the previous ProductQuery
*
*ProductFeed newItemsFeed = service.Query(query);*
*Console.WriteLine("After Refresh:");*
*Console.WriteLine("AccessToken: {0}", parameters.AccessToken);*
*Console.WriteLine("RefreshToken: {0}", parameters.RefreshToken);*
*
*
I'm not sure what could be causing your issue, but this successfully
retrieves products 1 and 2 in the feed and prints two distinct access
tokens and the same refresh token:

*Before Refresh:*
*AccessToken: ya29.AHES6ZT_...*
*RefreshToken: 1/8XTHm5z...*
*After Refresh:*
*AccessToken: ya29.AHES6ZQA_...*
*RefreshToken: 1/8XTHm5z...*

On Thu, May 17, 2012 at 10:38 AM, Caroline McLean <bbmcarol...@gmail.com>wrote:

...

read more »


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline McLean  
View profile  
 More options May 17 2012, 3:20 pm
From: Caroline McLean <bbmcarol...@gmail.com>
Date: Thu, 17 May 2012 12:20:30 -0700 (PDT)
Local: Thurs, May 17 2012 3:20 pm
Subject: Re: Oauth2 with .NET

Sorry I think my example was not complete enough.  I am using two separate
apps to request the token and then to use the token to get products.  I
store the auth token and the refresh token from the first app and use it in
my second app.  This is very close to how it will be used when implemented.
BTW there is no ContentForShoppingService(userAgent); that takes two
parameters in the .net wrapper, at least not in my version.

So to secure the auth token I do the following (sample code essentially)
--------------------------------------------------------------------------- --------------------------------------------------------------------------- -----------------------------------------------------------
        private static string redirectUri =
"https://localhost/oauth2callback.ashx"; // the magic url you suggested in
the meeting the other day is not                                    

                                     // acceptable for web applications -
only installed non web apps

        private static string scopes =
"https://www.googleapis.com/auth/structuredcontent
https://www.google.com/m8/feeds/
https://apps-apis.google.com/a/feeds/groups/";

            OAuth2Parameters parameters = new OAuth2Parameters()
            {
                ClientId = clientId,
                ClientSecret = clientSecret,
                RedirectUri = redirectUri,
                Scope = scopes,
                ApprovalPrompt = "force"
            };

            string url =
OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
            // code parameter gained from pasting the above url into a
browser
            Console.WriteLine("Authorize URI: " + url);
            parameters.AccessCode = Console.ReadLine(); // in the query
string copy and past the code parameter value here

            // this populates the parameter object - copy the values of the
authentication and refresh tokens to use for your authorization later
            OAuthUtil.GetAccessToken(parameters);

--------------------------------------------------------------------------- --------------------------------------------------------------------------- -----------------------------------------------------
            // in a separate app I run the following code
            ContentForShoppingService service = new
ContentForShoppingService(userAgent);

            OAuth2Parameters parameters = new OAuth2Parameters();
            parameters.AccessToken = authToken; // gained from first app
            parameters.RefreshToken = refreshToken; // gained from first app

            GOAuth2RequestFactory requestFactory = new
GOAuth2RequestFactory("structuredcontent", userAgent, parameters);
            //OAuthUtil.RefreshAccessToken(parameters);
            service.RequestFactory = requestFactory;

            // Retrieve the list of all existing products
            string projection = "schema";
            ProductQuery query = new ProductQuery(projection, accountId);
            ProductFeed feed = service.Query(query);

This works great for exactly one hour until the token expires and then it
fails.  The example you showed is doing it all in the same context, perhaps
there is more information I need to preserve from the parameters object
from the first application?  Does it work if you separate the auth process
into a separate application.  Essentially customers set up their google
accounts in one web application and then the scheduled job will be running
in a different context.  Besides that you dont want to be trading a token
for a url code everytime right? Once you have an auth token, you can
continue to use that without another code request, right? Or am I mistaken
here?

Thanks again for all of your help.
Caroline


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Daniel Hermes  
View profile   Translate to Translated (View Original)
 More options May 17 2012, 4:23 pm
From: Daniel Hermes <dher...@google.com>
Date: Thu, 17 May 2012 13:23:36 -0700
Local: Thurs, May 17 2012 4:23 pm
Subject: Re: Oauth2 with .NET

1) I am using a version supported by the most recent changes:
http://code.google.com/p/google-gdata/source/detail?r=1186
http://code.google.com/p/google-gdata/source/detail?r=1188
http://code.google.com/p/google-gdata/source/detail?r=1190

2) You also need your account data to do the refresh. In particular
ClientSecret and ClientId

If you trickle down the call stack, we have
- GOAuth2RequestFactory.CreateRequest returns GOAuth2Request

- In GOAuth2Request.Execute if HttpStatusCode is
Unauthorized, OAuthUtil.RefreshAccessToken is called

- RefreshAccessToken, OAuthBase.GetOAuth2AccessToken
and OAuthBase.GetRefreshAccessTokenRequestBody are called

- In OAuthBase.GetRefreshAccessTokenRequestBody, the client id and client
secret are used along with the refresh token

3) You should serialize every property you can/are comfortable with from
the OAuth2Parameters object and then reconstruct it

Regards,

On Thu, May 17, 2012 at 12:20 PM, Caroline McLean <bbmcarol...@gmail.com>wrote:

--
Daniel Hermes | Developer Programs Engineer | dher...@google.com | (504)
5DJ-GOOG

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Caroline  
View profile  
 More options May 18 2012, 2:29 pm
From: Caroline <devteam.uni...@gmail.com>
Date: Fri, 18 May 2012 11:29:48 -0700 (PDT)
Local: Fri, May 18 2012 2:29 pm
Subject: Re: Oauth2 with .NET

BTW using the client secret and client Id worked like a charm and just
saving the refresh token and auth token were sufficient...almost there :)


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
sharon.jefferson-tet...@abelandcole.co.uk  
View profile  
 More options Jan 10, 5:18 am
From: sharon.jefferson-tet...@abelandcole.co.uk
Date: Thu, 10 Jan 2013 02:18:21 -0800 (PST)
Local: Thurs, Jan 10 2013 5:18 am
Subject: Re: Oauth2 with .NET

Hi Caroline,

Did you get this to work?  If so, could you please post some sample code?  
I have exactly the same issue.

Thanks,

Sharon


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »