How do I prevent the user from being asked to grant permissions for a Google Apps Marketplace app that the domain administrator has approved - single-sign-on

I've been trying to convert an old style Marketplace app to the new way of doing things, but I keep having the user prompted for authorization when they first follow the Universal Navigation link (the app was installed onto the domain via the 'Test Install Flow' link on the marketplace SDK).
When I request the 'openid email' scopes, the prompt appears, but if I specify a separate scope (instead of, not in addition to 'openid email') that is part of the app, it doesn't prompt the user for auth (unless I request offline access, which I want for parity of features with the previous version, but one problem at a time...).
Sample code using the google api nodejs client:
var http = require('http');
var googleapis = require('googleapis');
var url_parse = require('url');
var OAuth = googleapis.auth.OAuth2;
var client = new OAuth(
CLIENT_ID
CLIENT_SECRET
REDIRECT_URL
);
http.createServer(dispatcher).listen(80);
function dispatcher(req, res){
res.writeHead(200, {'Content-Type': 'text/html'});
var url = url_parse.parse(req.url, true);
if(url.pathname === '/auth') {
auth_time(res);
} else if (url.pathname === '/callback') {
console.log('looking good');
client.getToken(url.query.code, function(err, tokens){
console.log(tokens);
client.setCredentials(tokens);
res.end(render_page('yep'));
});
} else {
res.end(render_page('different page'));
console.log(req.url);
}
}
function auth_time(res){
res.end(render_page('<a href="'+client.generateAuthUrl({
scope: 'openid email https://www.google.com/m8/feeds', //Prompts
// scope: 'https://www.google.com/m8/feeds', //Doesn't prompt
include_granted_scopes: 'true',
access_type: 'online'
})+'">Click for auth</a>'));
}
function render_page(contents){
return '<html><head><title>The page</title></head><body>'+contents+'</body></html>';
}
This similar question has an answer suggesting that https://www.googleapis.com/auth/plus.me is added to the list of scopes used on the Marketplace SDK, but that scope is removed on page refresh (I'm guessing it is treated as identical to one or both of https://www.googleapis.com/auth/userinfo.email & https://www.googleapis.com/auth/userinfo.profile which are automatically set as scopes and are not removable.

Related

POST data to Google Sheet web app from AWS Lambda

CURRENTLY
I have a Google Sheets App Script 'web app'
Script in Goolge Sheets
function doPost(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A1").setValue("Hello!")
return "Success!"
}
Google Apps Script Web App Config:
Execute as: Me // or as User. I've tried both.
Who has access: Anyone within MyOrganisation
I want to make a POST request to the above Web App from AWS Lambda.
AWS Lambda .js:
const { GoogleSpreadsheet } = require("google-spreadsheet");
const doc = new GoogleSpreadsheet(
{spreadsheetId}
);
await doc.useServiceAccountAuth({
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n"),
});
let token = doc["jwtClient"]["credentials"]["access_token"];
await new Promise((resolve, reject) => {
const options = {
host: 'script.google.com',
path: "/macros/s/{myscriptid}/exec", //<-- my web app path!
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': "Bearer "+ token
}
};
//create the request object with the callback with the result
const req = HTTPS.request(options, (res) => {
resolve(JSON.stringify(res.statusCode));
});
// handle the possible errors
req.on('error', (e) => {
reject(e.message);
});
//do the request
req.write(JSON.stringify(data));
//finish the request
req.end();
});
console.log("response:"+JSON.stringify(response))
GCP Service Account
I have a GCP Service Account, with permission to Google Sheets API, and otherwise unrestricted access.
This Service account has EDIT access to the Google Sheet with the doPost(e) script.
Token Output:
"jwtClient": {
"_events": {},
"_eventsCount": 0,
"transporter": {},
"credentials": {
"access_token": "somelongvalue...............", //<-- what I use
"token_type": "Bearer",
"expiry_date": 1661662492000,
"refresh_token": "jwt-placeholder"
},
"certificateCache": {},
"certificateExpiry": null,
"certificateCacheFormat": "PEM",
"refreshTokenPromises": {},
"eagerRefreshThresholdMillis": 300000,
"forceRefreshOnFailure": false,
"email": "serviceaccount#appspot.gserviceaccount.com",
"key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
"scopes": [
"https://www.googleapis.com/auth/spreadsheets"
],
"subject": null,
"gtoken": {
"key": "-----BEGIN PRIVATE KEY-----\nsomelongvalue=\n-----END PRIVATE KEY-----\n",
"rawToken": {
"access_token": "somelongvalue...............",
"expires_in": 3599,
"token_type": "Bearer"
},
"iss": "serviceaccount#appspot.gserviceaccount.com",
"sub": null,
"scope": "https://www.googleapis.com/auth/spreadsheets",
"expiresAt": 1661662492000
}
}
ISSUE
Current response:
response:"401"
I cannot find any Google documentation on how to setup the headers to authenticate a request (from my service account) to my organisation restricted web app.
When the Web App is open to "Anyone" then it runs fine, but as soon as I restrict to MyOrganisation, I struggle to find a way to authenticate my POST request.
HELP!
How do I set up a POST request to my Google Sheets web app such that it can be protected by authentication? Right now, I'd be happy to find ANY means to authenticate this request (not necessarily a service account) that doesn't leave it completed open to public.
Should I use this hack?
One idea I had was to put a "secret" into my lambda function, and then make the web app public. The web app would check the secret, if if matched, would execute the function.
Modification points:
In order to access Web Apps using the access token with a script, the scopes of Drive API are required to be included. Those are https://www.googleapis.com/auth/drive.readonly, https://www.googleapis.com/auth/drive, and so on. Ref
When I saw your showing script, it seems that the access token is retrieved using google-spreadsheet. When I saw the script of google-spreadsheet, it seems that this uses only the scope of https://www.googleapis.com/auth/spreadsheets. Ref
From this situation, I thought that the reason for your current issue might be due to this. If my understanding is correct, how about the following modification? In this modification, the access token is retrieved by googleapis for Node.js from the service account. Ref
Modified script:
Google Apps Script side:
function doPost(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A1").setValue("Hello!")
return ContentService.createTextOutput("Success!"); // Modified
}
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
Node.js side:
const { google } = require("googleapis");
const HTTPS = require("https");
const auth = new google.auth.JWT(
"###", // Please set client_email here.
null,
"###", // Please set private_key here. When you set private_key of service account, please include \n.
["https://www.googleapis.com/auth/drive.readonly"],
null
);
function req(token) {
return new Promise((resolve, reject) => {
const data = { key1: "value1" }; // Please set your value.
const options = {
host: "script.google.com",
path: "/macros/s/{myscriptid}/exec", //<-- my web app path!
method: "POST",
headers: {Authorization: "Bearer " + token},
};
const req = HTTPS.request(options, (res) => {
if (res.statusCode == 302) {
HTTPS.get(res.headers.location, (res) => {
if (res.statusCode == 200) {
res.setEncoding("utf8");
res.on("data", (r) => resolve(r));
}
});
} else {
res.setEncoding("utf8");
res.on("data", (r) => resolve(r));
}
});
req.on("error", (e) => reject(e.message));
req.write(JSON.stringify(data));
req.end();
});
}
auth.getAccessToken().then(({ token }) => {
req(token).then((e) => console.log(e)).catch((e) => console.log(e));
});
When this script is run, when the Web Apps is correctly deployed, the script of Web Apps is run and Success! is returned.
Note:
If this modified script was not useful for your Web Apps setting, please test as follows.
Please confirm whether your service account can access to the Spreadsheet again.
Please share the email address of the service account on the Spreadsheet. From your showing Google Apps Script, I thought that your Google Apps Script is the container-bound script of the Spreadsheet.
Please reflect the latest script to the Web Apps.
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
When you set private_key of service account, please include \n.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
Added:
When you will directly put the value to the Spreadsheet using Sheets API with google-spreadsheet module, you can also use the following script.
const { GoogleSpreadsheet } = require("google-spreadsheet");
const sample = async () => {
const doc = new GoogleSpreadsheet("###"); // Please set your Spreadsheet ID.
await doc.useServiceAccountAuth({
client_email: client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
private_key: process.env.GOOGLE_PRIVATE_KEY,
});
await doc.loadInfo();
const sheet = doc.sheetsByTitle["Sheet1"];
await sheet.loadCells("A1");
sheet.getCell(0, 0).value = "Hello!";
await sheet.saveUpdatedCells();
};
sample();
In this case, your service account is required to be able to access to the Spreadsheet. Please be careful about this.

google-api-nodejs-client: how to call google+ domain api locally? (by the plusDomains.media.insert)

I am going to use the Nodejs google api client(google-api-nodejs-client) to post a photo to my google+. (I have listed all my code at end of this post.)
Let me introduce a little bit background:
I have created a project on: console.developers.google.com
I have enabled google+ domain API for this project.
I have created credentials for this project as well. (it is a OAuth 2.0 client ID)
I have a little bit experience of using the client (google-api-nodejs-client) and I can post images and files to my google drive by it.
However, posting to google+ photo is different, the auth is the key different. I have tried several different ways, but none of them works.
The api always return me this:
{ [Error: Forbidden]
code: 403,
errors: [ { domain: 'global', reason: 'forbidden', message: 'Forbidden' } ] }
I also found this:
Warning: The Google+ Sign-In button and the plus.login scope used by
Google+ Sign-In, are not currently supported for use with the Google+
Domains API. Requests that are made to the Google+ Domains API using
an authentication token granted for the
www.googleapis.com/auth/plus.login scope, or generated by the
Google+ Sign-In button, will fail.
If it doesn't support the sign-button, what does it support?
This page tell me to add a domain delegation (https://developers.google.com/+/domains/authentication/delegation), but i haven't push my program into any server, i just try to run it locally.
I was wondering if it is possible to use this client to post photo to google+ by run a nodejs program locally?
var CLIENT_ID = "xxxxxxx.apps.googleusercontent.com";
var CLIENT_SECRET = "xxxxxxxx";
var REDIRECT_URL = "https://xxxxxxx";
var readline = require('readline');
var async = require('async');
var google = require('googleapis');
var request = require('request');
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function getAccessToken (oauth2Client, callback) {
// generate consent page url
var scopes = [
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/plus.stream.read',
'https://www.googleapis.com/auth/plus.stream.write',
'https://www.googleapis.com/auth/plus.circles.read',
'https://www.googleapis.com/auth/plus.circles.write',
'https://www.googleapis.com/auth/plus.media.upload'
];
var url = oauth2Client.generateAuthUrl({
access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
scope: scopes, // If you only need one scope you can pass it as string,
key: 'p7UALH460Deqodhvb2zESYya'
});
console.log('Visit the url: ', url);
rl.question('Enter the code here:', function (code) {
// request access token
oauth2Client.getToken(code, function (err, tokens) {
if (err) {
return callback(err);
}
// set tokens to the client
// TODO: tokens should be set by OAuth2 client.
oauth2Client.setCredentials(tokens);
console.dir(tokens);
callback();
});
});
}
getAccessToken(oauth2Client, function () {
var plusDomains = google.plusDomains({ version: 'v1', auth: oauth2Client });
var requestObj = request({url:'http://asset1.cxnmarksandspencer.com/is/image/mands/2643f540b32fe8c6cccdec95b3a2c5239166232f?$editorial_430x430$'});
const Readable = require('stream').Readable;
var iamgeStream = new Readable().wrap(requestObj);
plusDomains.media.insert({
userId: 'me',
collection: 'cloud',
resource: {
name: 'testimage.png',
mimeType: 'image/png'
},
media: {
mimeType: 'image/png',
body: iamgeStream
},
access:{domainRestricted :"true"}
}, callbackFn);
function callbackFn(argument) {
console.dir(argument);
}
});
Thanks you very much!
Peter

Error 500 backendError with Gmail API and Google APIs Node Client

I'm trying to use the new Gmail API with the Google API Node client. I created a new project from the developer console, set up a new "Service Account" Client ID, and enabled access to the API.
As a proof of concept, I am simply trying to list the threads in my inbox. When I enable the OAuth 2.0 toggle for the API explorer and enter my email address, the request succeeds and I see a JSON response with data.
Now I try to do the same in Node:
var googleapis = require('googleapis');
var SERVICE_ACCOUNT_EMAIL = '...SNIP...';
// generated by: openssl pkcs12 -in ...SNIP...p12 -out key.pem -nocerts -nodes
var SERVICE_ACCOUNT_KEY_FILE = 'key.pem';
var jwt = new googleapis.auth.JWT(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_KEY_FILE,
null,
['https://www.googleapis.com/auth/gmail.readonly']);
googleapis
.discover('gmail', 'v1')
.execute(function(err, client) {
jwt.authorize(function(err, result) {
if(err) console.error(err);
else console.log(result);
client.gmail.users.threads.list()
.withAuthClient(jwt)
.execute(function(err, result) {
if(err) console.error(err);
else console.log(result);
});
});
});
First I print the results of the authorize() call, which looks like it returns a token, so I think I have all the OAuth stuff setup properly:
{ access_token: '...SNIP...',
token_type: 'Bearer',
expires_in: 1404277946,
refresh_token: 'jwt-placeholder' }
Then I try to actually use the API, but I get an error:
{ errors:
[ { domain: 'global',
reason: 'backendError',
message: 'Backend Error' } ],
code: 500,
message: 'Backend Error' }
At this point, I don't know what else to try. I think the OAuth stuff is working properly, because I haven't gotten any authentication errors. I also think the API itself is working and my account is fine, because I can use it through the API Explorer. I don't see any indication that the Node library is at fault either. In short, I have no idea what the problem is. Any ideas?
You are using the Service Account to authenticate your requests to GMail. Your Service Account will not have a Gmail as far as I know, only users have GMail. For this reason you will need to do the OAuth2 flow with the user (see here for example).

PhoneGap 3.3 using Phonegap Facebook Connect plugin, getLoginStatus always returns unknown

I'm trying to implement Phonegap Facebook Connect plugin via PhoneGap build and FB.getLoginStatus ALWAYS returns "unknown" even though I'm logged into Facebook and have granted access to my app. Here's my code:
JAVASCRIPT CODE:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady()
{
FB.init
({
appId: 'XXXXX',
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: false, // parse XFBML
oauth : true ,// enable OAuth 2.0
useCachedDialogs: false,
nativeInterface : CDV.FB
});
FB.getLoginStatus(function (response)
{
alert('FB.getLoginStatus');
if (response.status === 'connected')
{
alert('DUDE: connected to facebook');
}
else if (response.status === 'not_authorized')
{
alert('DUDE: not authorized for facebook');
}
else
{
alert('DUDE: not logged in to facebook: ' + response.status);
}
}, true);
}
CONFIG.XML:
<gap:plugin name="com.phonegap.plugins.facebookconnect">
<param name="APP_ID" value="XXXXXXX" />
<param name="APP_NAME" value="APP NAME" />
</gap:plugin>
Any ideas on why facebook auth status is unknown? Thanks.
You need to go through "Facebook Requirements and Set-Up" In Facebook Connect plugin
in Android:
If you plan on rolling this out on Android, please note that you will need to generate a hash of your Android key(s) and submit those to the Developers page on Facebook to get it working. Furthermore, if you are generating this hash on Windows (specifically 64 bit versions), please use version 0.9.8e or 0.9.8d of OpenSSL for Windows and not 0.9.8k. Big ups to fernandomatos for pointing this out!
step detail:
1. generate a hash key(s) How to create Android Facebook Key Hash?
2. insert your hash key on facebook app setting panel( Settings ) (add Android platform and insert Key Hashes)
3. Go to Account > Edit Setting > Signing Key's tab in Adobe phonegap build then Click 'add a key...' upload your keystore file to make a Android buuiding key
4. select your android key to build app in phonegap build.
reference link:
login + logout + login = fail #1
This worked for me use the plug with the and the example
https://github.com/Wizcorp/phonegap-facebook-plugin/blob/a5c6be9/README.md
You can't relay on cookies and need to pass the access token by yourself.
Here is what you need to do:
1) Client side (note that I am using the older version of the plugin where the FB js was patched instead of new functions):
Pass the user id and accesstoken to the server:
FB.login(function(response) {
if (response.authResponse) {
// Use userID on authResponse because FB.getUserID() works in the browser but return null on device
var userId = response.authResponse.userID;
// Or use FB.getAccessToken()
var accessToken = response.authResponse.accessToken;
//use userId and accessToken to pass to the server (form or ajax call)
}
}
2) Server Side (php)
//Get the accessToken from the request
$accessToken = $_REQUEST['accessToken'];
$facebook = new Facebook(array(
'appId' => '<YOUR APP ID>',
'secret' => '<YOUR APP SECRET>'
));
$facebook->setAccessToken($accessToken);
//Now you have the right session setup and can call Graph API
$fbUser = $facebook->api('/me')

Facebook Auth with AngularJS and Django REST Framework

I am developing a SPA application with AngularJS which uses Django backend for the server. The way that I communicate with the server from the SPA is with django-rest-framework. So now I want to make authentication with facebook (google and twitter too) and I read a lot on this topic and found OAuth.io which is making the authetication on the client SPA side and python-social-auth which is doing the same thing but on the server side.
So currently I have only the client auth, my app is connecting to facebook (with OAuth.io) and login successfully. This process is returning access_token and then I am making a request to my API which have to login this user or create account for this user by given token and this part is not working. So I am not sure where I am wrong, maybe because there isn't a full tutorial about using python-social-auth so maybe I am missing something or.. I don't know..
So some code of this what I have:
On the SPA side: This is the connection with OAuth.io and is working because I am getting the access token. Then I have to make a request to my rest API. backend is 'facebook', 'google' or 'twitter'
OAuth.initialize('my-auth-code-for-oauthio');
OAuth.popup(backend, function(error, result) {
//handle error with error
//use result.access_token in your API request
var token = 'Token ' + result.access_token;
var loginPromise = $http({
method:'POST',
url: 'api-token/login/' + backend + '/',
headers: {'Authorization': token}});
loginPromise.success(function () {
console.log('Succeess');
});
loginPromise.error(function (result) {
console.log('error');
});
});
On the server in my settings.py I have added social plugin to the installed apps, template context preprocessors, some auth backends and that is my file:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
...,
'rest_framework',
'rest_framework.authtoken',
'api',
'social.apps.django_app.default',
'social'
)
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.request",
"django.contrib.messages.context_processors.messages",
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
SOCIAL_AUTH_FACEBOOK_KEY = 'key'
SOCIAL_AUTH_FACEBOOK_SECRET = 'secret'
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
AUTHENTICATION_BACKENDS = (
'social.backends.open_id.OpenIdAuth',
'social.backends.facebook.FacebookOAuth2',
'social.backends.facebook.FacebookAppOAuth',
'social.backends.google.GoogleOpenId',
'social.backends.google.GoogleOAuth2',
'social.backends.google.GoogleOAuth',
'social.backends.twitter.TwitterOAuth',
'django.contrib.auth.backends.ModelBackend',
)
In my views.py of the API I have the following (I found it here):
from django.contrib.auth.models import User, Group
from rest_framework import viewsets, generics
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions, parsers, renderers
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.decorators import api_view, throttle_classes
from social.apps.django_app.utils import strategy
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
class ObtainAuthToken(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
model = Token
# Accept backend as a parameter and 'auth' for a login / pass
def post(self, request, backend):
serializer = self.serializer_class(data=request.DATA)
if backend == 'auth':
if serializer.is_valid():
token, created = Token.objects.get_or_create(user=serializer.object['user'])
return Response({'token': token.key})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
# Here we call PSA to authenticate like we would if we used PSA on server side.
user = register_by_access_token(request, backend)
# If user is active we get or create the REST token and send it back with user data
if user and user.is_active:
token, created = Token.objects.get_or_create(user=user)
return Response({'id': user.id , 'name': user.username, 'userRole': 'user','token': token.key})
#strategy()
def register_by_access_token(request, backend):
backend = request.strategy.backend
user = request.user
user = backend._do_auth(
access_token=request.GET.get('access_token'),
user=user.is_authenticated() and user or None
)
return user
And finally I have these routes in urls.py:
...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token'),
url(r'^api-token/login/(?P<backend>[^/]+)/$', views.ObtainAuthToken.as_view()),
url(r'^register/(?P<backend>[^/]+)/', views.register_by_access_token),
...
Everytime when I try to do auth, OAuth.io is working and the rqest to api returns
detail: "Invalid token"
I think that I missed something in the configuration of python-social-auth or I am doing everything wrong. So I will be glad if anyone has some ideas and want to help :)
Add the following line to your ObtainAuthToken class
authentication_classes = ()
and your error {"detail": "Invalid token"} will go away.
Here's why...
Your request contains the following header
Authorization: Token yourAccessToken
yet you have defined rest_framework.authentication.TokenAuthentication in DEFAULT_AUTHENTICATION_CLASSES.
Based on this Django thinks you want to perform token authentication as you have passed a Token in. It fails because this is an access token for facebook and doesn't exist in your django *_token database, hence the invalid token error. In your case all you need to do is tell Django not to use TokenAuthentication for this view.
FYI
Keep in mind you may encounter further errors as your code execution was halted before the post method of ObtainAuthToken executed. Personally when trying to step through your code I got the error
'DjangoStrategy' object has no attribute 'backend'
on
backend = request.strategy.backend
and resolved it by changing to
uri = ''
strategy = load_strategy(request)
backend = load_backend(strategy, backend, uri)
Additionally you should update your you register_by_access_token function as it doesn't line up with the working code from the blog you referenced. The blog author posted his latest code here. Your version doesn't pull the token out of the auth header which is required if you want to use it to auth with a third party like facebook.
Yea. Solved. The settings are not right and you need to add permissions.
REST_FRAMEWORK = {
# Use hyperlinked styles by default.
# Only used if the `serializer_class` attribute is not set on a view.
'DEFAULT_MODEL_SERIALIZER_CLASS':
'rest_framework.serializers.HyperlinkedModelSerializer',
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
and some info about pipeline:
SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details',
'social.pipeline.social_auth.social_uid',
'social.pipeline.social_auth.auth_allowed',
'social.pipeline.social_auth.social_user',
'social.pipeline.user.get_username',
'social.pipeline.social_auth.associate_by_email',
'social.pipeline.user.create_user',
'social.pipeline.social_auth.associate_user',
'social.pipeline.social_auth.load_extra_data',
'social.pipeline.user.user_details'
)
I'm using tools just like you, but I provide my login/register/.... with
django-allauth package, and then use django-rest-auth for API handling.
You just need follow the installation instruction, then use them for your rest APIs.
Adding allauth and rest-auth to your INSTALLED_APPS:
INSTALLED_APPS = (
...,
'rest_framework',
'rest_framework.authtoken',
'rest_auth'
...,
'allauth',
'allauth.account',
'rest_auth.registration',
...,
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
)
Then add your custom urls:
urlpatterns = patterns('',
...,
(r'^auth/', include('rest_auth.urls')),
(r'^auth/registration/', include('rest_auth.registration.urls'))
)
Finally, add this line:
TEMPLATE_CONTEXT_PROCESSORS = (
...,
'allauth.account.context_processors.account',
'allauth.socialaccount.context_processors.socialaccount',
...
)
These two packages works like a charm, and you don't need to have concern about any type of login.registration, because allauth package handles both django model login and oAuth login.
I hope it helps