Non persistent Authentication cookie in a SPA AngularJS / Django REST - django

I have been wrestling with this issue for several hours:
I have a Single-Page Application written in Angular which communicates with a DjangoREST backend. I am trying to implement an auth fonction with session Cookies. The way I see it is:
1/ Show any unlogged visitor a login page
2/ Make a POST to url/login with the credentials
3/ Obtain a "sessionid" cookie and writing in a service that the user is logged
4/ Redirect vistor towards reserved content and used get & post to access contents with the cookie
The login endpoint is already set and works. When I make a post, I receive a HTTP 200 response with user info and a Set-Cookie, but subsequent calls do not contain the Cookie:
Request URL: ...
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:38
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:devinify1.herokuapp..
Origin:http://mobilevinify.herokuapp...
Referer:http://mobilevinify.herokuapp...
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Form Dataview sourceview URL encoded
username:felix#vinify.co
password:test
Response Headersview source
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:189
Content-Type:application/json
Date:Sat, 14 Dec 2013 20:45:14 GMT
Server:gunicorn/18.0
Set-Cookie:sessionid=ijz27zy655qn0cwmlnvr66609hsyvdub; expires=Sat, 28-Dec-2013 20:45:14 GMT; Max-Age=1209600; Path=/
Vary:Cookie
My code is a very simple adaptation of the angular-app example:
https://github.com/FelixLC/MobileWebApp/blob/master/app/scripts/security/security.js
I have tried this on localhost et on heroku. The server and the client are on different domains, CORS are allowed.
When I try to make calls, I receive an error from Django
TypeError at /vinibarwines/
int() argument must be a string or a number, not 'AnonymousUser'
Should I try to get this cookie and put it in the headers with angularJS?
You can try to login at http://mobilevinify.herokuapp.com/#/login with felix#vinify.co & test. Then Click on Vinibar, there is a 500 internal error on the GET request
Any help much appreciated
Felix

Here is the full layout of how I actually do my authentication. Django/Angular Authentication. It's a pretty extensive response, I'm more than happy to answer further questions you might have.

Related

rejected by cors when using withCredentials, despiete access-control-allow-credentials and origin are set

I'm using AWS lambdas and cloudfront to serve a SPA.
Now that my lambdas are setting a cookie, I want to include that cookie in the requests I made to the backend (the cookie is HttpOnly and Secure).
Using Axios I set the withCredentials option to true and all my request are now being rejected because CORS.
The web app is being served from the main domain, while the backend lambdas are on the usual lambda weird UUID url. The lambdas are returning the proper headers, as you can see in the screenshot: access-control-allow-origin is set to the domain the web-app is being served from and access-control-allow-credentials is true. The screenshot is from the app without the withCredentials option activated, so it is being triggered from the web-app 100% sure.
Everything is being served over https with a valid certificate (I want to test this also on localhost, but that is a different story)
This is the error I'm getting on the console. One weird thing is that it claims that Access-Control-Allow-Credentials is set to '', which is not true
Access to XMLHttpRequest at 'https://p3doiszvgg.execute-api.eu-central-1.amazonaws.com/dev/sessions'
from origin 'https://pento.danielo.es' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Is there anything missing?
EDIT:
This are the headers that I'm sending. The problem with this headers is that they are obtained without the withCredentials flag, because if I add such flag the only headers I can see are the provisional headers.
:authority: p3doiszvgg.execute-api.eu-central-1.amazonaws.com
:method: POST
:path: /dev/sessions
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en;q=0.9,es-ES;q=0.8,es;q=0.7,en-US;q=0.6
authorization: Bearer the.bearer.token
cache-control: no-cache
content-length: 58
content-type: application/json;charset=UTF-8
origin: https://pento.danielo.es
pragma: no-cache
referer: https://pento.danielo.es/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
Here is a provisional headers screenshot:
The cookie sent by the server looks something like this:
Set-Cookie: refresh_token=uuid-string-with-letters-numbers; HttpOnly; Secure;
Finally I found the problem and a temporary solution (I'm not very happy with it).
The problem was not my lambda response, that was correct and including the required headers, the problem was with the preflight request. Your browser will send a preflight request almost for every CORS request you made, and, while that request was being successful it was missing some headers. This can be very confusing because the request that it is failing is your actual request (that is what the browser flags as failed) but the problem is on the preflight response.
To be fair, the error on the console was already pointing this out:
Response to preflight request doesn't pass access control check
But it is abit buried, easy to miss and the documentation about it is sparse.
The way I fixed it is by adding some extra props to the CORS definition of my serverless template:
authEcho:
handler: src/users/me.handler
events:
- http:
path: me
method: get
cors:
origin: https://frontend.domain.es
allowCredentials: true # <-- this is the key part
It is not clear on the serverless documentation, but those will be merged with the final response, so you don't need to specify everything or all the headers. The only thing I don't like is that I have to hardcode the origin, while on the actual labmda responses I can calculate it dynamically.

Error 401 on WEB API 2 when there is lot of request from Android device

I’m developing an Android App and a Web Service that communicate. My Web Service is in WEB API 2 with token bearer authentication.
My problem is that when I send too many requests (~20 request in 15 seconds) to my Web Service from my Android App, the WS response with
“401” : “Authorization has been denied for this request”
This happen ONLY on the production server (Amen hoster) AND from the Android Device. For example, if I try with Postman, everything works fine. So it’s related to my production server and/or my android app request.
The code for access to the Web Service
URL obj = new URL(SERVEUR_URL + url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", "Bearer " + token);
con.setRequestProperty("Content-Type", "application/json");
int responseCode = con.getResponseCode();
String responseMessage = con.getResponseMessage();
The authentication provider on my Web Service is the default one. No modifications.
The request from my Android App (not work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Authorization: Bearer XXXX
Content-Type: application/json
User-Agent: Dalvik/2.1.0 (Linux; U; Android 6.0; Google Nexus 5X - 6.0.0 - API 23 - 1080x1920 Build/MRA58K)
Host: api.xxxx.com
Connection: Keep-Alive
Accept-Encoding: gzip
The request from Postman (work every time)
GET http://api.xxxx.com/api/Weesps/GetAvailableWeesps HTTP/1.1
Host: api.xxxx.com
Connection: keep-alive
Authorization: Bearer XXXX
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Postman-Token: bca55154-775d-9709-7a8b-4793393890ad
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: dadaproaffinity=14ff51cc869a14d3552485cb4ceee1faa1be7165cc5d4b0e2b19370f11afcbea
What I have tried:
Reproduce this error in local : it works fine on local server (web and SQL servers) from android app or from Postman
I check that the token was sent correctly in every requests
The request from Android is the same every time
Tried to add missing header to my android app request
I spend two days on this problem and read many stackoverflow posts but no one helps me.
Thanks for your help.
UPDATE 1 :
With Fiddler I saw that in GET request from Postman, they were a Cookie header. This cookie is sent when we ask for a bearer token.
Example of token response from the server
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 691
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.5
Set-Cookie: .AspNet.Cookies=XXXX; path=/; HttpOnly
X-Powered-By: ASP.NET
X-Powered-By: ARR/2.5
Date: Tue, 31 May 2016 16:55:39 GMT
{"access_token":"XXXX","token_type":"bearer","expires_in":1209599,"userName":"Foo",".issued":"Tue, 31 May 2016 16:55:40 GMT",".expires":"Tue, 14 Jun 2016 16:55:40 GMT"}
Fiddler and Postman saved this cookie and they automatically put it in requests to API (example on the “The request from Postman” code block). When I remove the cookie from the Postman GET request, it doesn’t work (just like my android app).
Now, the question is: why WEB API 2 send a cookie instead of only using the token ? And why the token work great in the first requests and don’t work properly for the following requests ?
According to ASP.NET WebAPI2 flow you can see on the bottom of that page, it seems your requests are always authenticated but sometimes fail to get authorized.
So imo, the AuthorizationFilter[Authorize] rejects some of your requests for an unknown reason. What I would suggest is to dump the request your API receives as well as the claims identity attached to the token. Try to see if there is differences between them when you have a successful response and when you have a 401.
That way, you may be able to determine either it is your request that got malformed, if it is the claims identity that is not good or if it is the AuthorizationFilter that refuses you for another reason (like too much queries or else).
Good luck !
UPDATE 1
According to your new input, I think that your Web API is configured to use both token and cookie authentication.
What I see here is you have two solutions :
1°/ Store the returned cookie in your Android application and use it for next calls. Simplest and fastest way to solve your problem without changing all your API, but you store an authorization cookie : it can leads to security problem (CSRF attacks).
2°/ You can check how your authentication and authorization filters are set to disable cookie authentication and only rely on token authentication : it will hence forces all the requests and your API to only use token and will prevents you from suffering CSRF attacks. More complex because you have to dig into your web API configuration.
Check the following links (sorry, as I don't have enough reputation yet to post more than 2 links per post, you'll find them as text at the end of my answer) :
ASP.net Secure a Web API 2.2[2] : From the chapter "Configuring the Authorization Server" at the bottom
MSDN article on Web API security[3] : More general and technical information about web api security, how to secure it and CRSF attacks
StackOverflow .NET cookie and token authentication[4] : Check David Banister's answer, I think it is exactly what you want to do : Only use token for all your API calls.
StackOverflow Authorize filter and authentication[5] : More information about such mechanisms for your API
And finally
Cookie authentication with web API and 401 codes[6] : Sounds like your actual problem, isn't it ?
I hope it helps you, good luck !
// Links
2: www.asp.net/web-api/overview/security/individual-accounts-in-web-api
3: msdn.microsoft.com/en-us/magazine/dn201748.aspx
4: stackoverflow.com/questions/22568409/mvc-net-cookie-authenticated-system-acessing-a-web-api-with-token-authenticatio
5: stackoverflow.com/questions/21231751/authorize-filter-and-authentication
6: brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
Finally, I got my answer:
My Web Service send a Cookie named “dadaproaffinity” the first time I ask for a request. This Cookie was automatically put on the following request by Postman but not by Android HttpUrlConnection. So, I just take this Cookie and now I just add this Cookie on every requests with the Token.
But : This cookie is send by IIS, not by my Web Service ! That’s why it works on local but not on the production server. I googled this cookie and there are very few responses about that. The only one that I find in English is :
Technical Cookie of IIS Server hosting the site.
Need to route to the correct server session, in order to keep it active
Does anyone have more information about this IIS Cookie ?

Word document streamed to HTTP response causes 401 authentication demand

Good morning all,
I have a web app using Classic ASP, hosted on IIS 7.5. I need to create a word document and stream back to the client for display, however when the document is streamed into the response something (an IIS setting?) is causing a 401 error - and i cannot track it down.
A colleague very kindly furnished me with some C++ code which deals with the document building & streaming and an ASP page which builds the COM objects and makes the calls etc.
The document starts life as a template in an IIS virtual directory outside my ASP application. We make a copy, do some find and replace actions and then stream it into the response with the correct MIME type for the browser to handle it however it sees fit.
It seems as soon as the streaming takes place (via a call to ASPTypeLibrary::IResponsePtr piResponse->BinaryWrite()) the 401 response is sent back, until that moment the response looks fine.
The site uses Forms authentication, and i have by this point signed in, the request i see in fiddler definitely has valid session data and the rest of the site is happy with my authentication.
Any ideas? (he asks with a note of desperation)
p.s. I realise i haven't listed all the code, i can if it helps though...
The plot thickens...
I have had success using the ASP page to stream the file into the output using and ADODB.Stream object.
When this is successful Fiddler picks up two HTTP request/responses; the first request gets a 401 back, then the browser sends another request with different cookie data which returns a successful result.
When my COM object is used two requests occur, but the second request also receives a 401...
Points to some security setting to do with COM object? Something i am not adding to the response with the COM object?
As per my response to Eric, my colleague worked a bit of magic and got the thing working, i am still a little confused about why it was caused though...
The line which Magic Al changed was this one:
piResponse->AddHeader( _T("Content-Length"), (LPCTSTR)Length );
Which is called while the response is being built up and what he did was comment it out.
Apparently he noticed that the length written by the BinaryWrite was coming out 13 bytes larger than the length of the file. He tells me that this may be because it is writing out the reserved WORD blocks from the Variant it is given.
So the response header is a bit mangled and the result is an HTTP violation error in fiddler which i had overlooked and somewhere in between client and COM object the mangled 200 response is replaced with a 401.
I guess the moral of this story is that you should always pay attention to fiddler errors and to ensure your Content-Length is correct.
My new question is why 401? why not a 500? And what is likely to be throwing this out? is it coming from IIS?
This is the HTTP text fiddler registers for the exchange:
GET GET [The page address - its on localhost and is an ASP page] HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: localhost
Cookie: SessionUID={E41F5378-FBE2-475E-8F9A-6416AFE2BAA0}; DisplayMethod=0; ShowDataTips=1; LOGONUSER={UserName Info}ASPSESSIONIDQARAQRBD={Session ID} Authorization: Negotiate YH8GBisGAQUFAqB1MHOgMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI/BD1OVExNU1NQAAEAAACXsgjiCwALADIAAAAKAAoAKAAAAAYBsR0AAAAPRE9DREVWLUpDV0RFVkVMT1BNRU5U
HTTP/1.1 401 Unauthorized
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
WWW-Authenticate: Negotiate oYIBYTCCAV2gAwoBAaEMBgorBgEEAYI3AgIKooIBRgSCAUJOVExNU1NQAAIAAAAWABYAOAAAABXCieJQEtMwe36vajD3zwEAAAAA9AD0AE4AAAAGAbEdAAAAD0QARQBWAEUATABPAFAATQBFAE4AVAACABYARABFAFYARQBMAE8AUABNAEUATgBUAAEAFABEAE8AQwBEAEUAVgAtAEoAQwBXAAQAOABEAGUAdgBlAGwAbwBwAG0AZQBuAHQALgBEAG8AYwB1AG0AYQB0AGkAbwBuAC4AYwBvAC4AdQBrAAMATgBEAE8AQwBEAEUAVgAtAEoAQwBXAC4ARABlAHYAZQBsAG8AcABtAGUAbgB0AC4ARABvAGMAdQBtAGEAdABpAG8AbgAuAGMAbwAuAHUAawAFACAARABvAGMAdQBtAGEAdABpAG8AbgAuAGMAbwAuAHUAawAHAAgAKRk7jhfZzQEAAAAA
Date: Thu, 13 Dec 2012 09:52:25 GMT
Content-Length: 341
Proxy-Support: Session-Based-Authentication
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Not Authorized</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Not Authorized</h2>
<hr><p>HTTP Error 401. The requested resource requires user authentication.</p>
</BODY></HTML>
------------------------------------------------------------------
GET [The page address - its on localhost and is an ASP page] HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Cookie: SessionUID={E41F5378-FBE2-475E-8F9A-6416AFE2BAA0}; DisplayMethod=0; ShowDataTips=1; LOGONUSER={UserName Info}ASPSESSIONIDQARAQRBD={Session ID}
Authorization: Negotiate oXcwdaADCgEBoloEWE5UTE1TU1AAAwAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAABXCiOIGAbEdAAAAD4GPyFfTAkcs1KpJqG4eT0ujEgQQAQAAAPUXp1AtIpqEAAAAAA==
Host: localhost
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Thu, 13 Dec 2012 09:52:27 GMT
Content-Length: 6630
Proxy-Support: Session-Based-Authentication
<HTML Page telling you about the error which gets displayed when you cancel the authentication dialog.>

HTTP sending response to OPTIONS request [C]

Getting Response is null error while receiving HTTP response.
I am developing an sample small HTTP server in C using row sockets.
There are actually 2 servers in my application one is standard Apache server which I am using for serving HTML pages and my small server will respond to only XMLHttpRequest sent from the Javascript within the HTML pages.
I am sending request from JavaScript as follows:
var sendReq = new XMLHttpRequest();
endReq.open("POST", "http://localhost:10000/", true);
sendReq.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
sendReq.onreadystatechange = handleResult;
var param = "REQUEST_TYPE=2002&userName=" + userName.value;
param += "&password=" + password.value;
sendReq.send(param);
When I send this request I receive following Request in my server code:
OPTIONS / HTTP/1.1
Host: localhost:10000
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.3) Gecko/20100423 Ubuntu/10.04 (lucid) Firefox/3.6.3
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://localhost:7777
Access-Control-Request-Method: POST
I have replied to this Request as follows using socket write function:
HTTP/1.1 200 OK\n
Access-Control-Allow-Origin: *\n
Server: PSL/1.0 (Unix) (Ubuntu/Linux)\n
Access-Control-Allow-Methods: POST, GET, OPTIONS\n
Accept-Ranges: bytes\n
Content-Length: 438\nConnection: close\n
Content-Type: text/html; charset=UTF-8\n\n
I don`t know What should be the HTTP actual response to be sent on request of OPTIONS.
After this I get my Actual POST request that I have sent from JavaScript and then I respond back with
HTTP/1.1 200 OK\n\n
And then at the browser end get error Response is null.
So how to send headers/data as HTTP Response using row sockets in 'C' and how to respond to OPTIONS request. Can someone explain me by giving some example?
It's hard to understand your question, but I believe you are pointing to this as the response giving you trouble:
HTTP/1.1 200 OK\n\n
You should be including other fields, especially the Content-Length and Content-Type. If you're going to build your own HTTP server, then you should review the protocol specifications.
That said, it's not at all clear why you need to replace the HTTP server instead of using either CGI or another server side language (PHP, Java, etc). This is significantly reducing your portability and maintainability.
Finally, you appear to be transmitting the password in the request. Make sure that this is only done over some kind of encrypted (HTTPS) or else physically secured connection.
I'm not sure what you're asking, but you might find the following useful:
HTTP Made Really Easy
HTTP/1.1 rfc2616.txt
MAMA - Opera Developer Community
I found them all quite useful when I was writing a HTTP client.
This problem had occured as after processing the OPTIONS request by our server, any subsequent requests made, for some reason, were required to be responded back with "Access-Control-Allow-Origin: *" along with other normal headers and response body.
After providing this line in our responses, I always got the desired responseText/responseXML in my javascript.

Google OpenID/federated login periodically fails

I'm developing a Django app that uses python-openid. The app is running on my development server at home.
Similar to stackoverflow's login mechanism, I'd like users to login to my website using their Google credentials.
The code I've implemented to do this, works well for a couple weeks, and then stops working. I get stuck during the login process on the following Google page: https://www.google.com/accounts/o8/ud with this message: "The page you requested is invalid." It'll randomly start working again, but fails every few weeks or so.
Going through Yahoo's login worked for months, and today has stopped working with the following message: "This page has expired, go back to the original page and please try again" on this page: https://open.login.yahooapis.com/openid/op/auth
Here is the request, as captured by LiveHttpHeaders for Google:
https://www.google.com/accounts/o8/ud
POST /accounts/o8/ud HTTP/1.1
Host: www.google.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042513 Ubuntu/8.04 (hardy) Firefox/3.0.10
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://127.0.0.1:8000/users/login/
Content-Length:907
openid.ax.if_available=ext1&openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&openid.realm=http://127.0.0.1:8000/accounts/login/&openid.return_to=http://127.0.0.1:8000/users/login/finish/?janrain_nonce=2009-10-05T19%3A10%3A11ZtioiRm&openid.ax.count.ext1=unlimited&openid.ax.mode=fetch_request&openid.sreg.optional=email&openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.ns.sreg=http://openid.net/extensions/sreg/1.1&openid.ns.ax=http://openid.net/srv/ax/1.0&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.assoc_handle=AOQobUcnzec0bpeZRztjqPrr5TQUA0aPL7SIuOPOMgWxex2HRAP09AyJ&openid.ax.required=ext0&openid.ax.type.ext0=http://schema.openid.net/namePerson&openid.ax.type.ext1=http://schema.openid.net/contact/web/default
HTTP/1.x 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
I'm not sure what's going on here, and would love some help.
It looks like the code you are using is generating a bad URL request. The real URL is https://www.google.com/accounts/o8/id, so try to fix the "ud" at the end changing it by an "id".
Hope this helps!
you can construct the uri and redirect the user to the uri with GET method. If you doing POST google expects some headers which I think it was not mentioned docs. Check the sample request. I tried with GET without python-openid it works pretty well.
You might take a look at the redirect_uri and the state inside to see if they match. I remember having the issue of having mismatched state sometimes ago with Google Login.
Btw if you use Django, I would recommend using social-app-django which is currently active and supports multiple social login options (if at some point you consider adding more social login providers).