2013-08-17 20 views
5

Non riesco a ottenere il token di accesso su Quizlet (oauth2). Tutto funziona bene fino ad ora, posso fare l'utente ad accettare il mio app sul Quizlet, ottenere reindirizzato, ma quando si richiede il token di accesso via NSURLConnection, ho sempre arrivare il seguente errore:Parametro grant_type non valido o parametro mancante su POST per la richiesta di token di accesso

2013-08-17 09:39:33.422 Abiliator[49549:c07] Returned data in string format: {"http_code":400,"error":"invalid_request","error_title":"Not Allowed","error_description":"Invalid grant_type parameter or parameter missing"}

Ecco il codice per l'autenticazione degli utenti (deve essere via browser secondo le specifiche):

- (void) authenticateQuizletUser 
{ 

NSString *quizletRandomString = [abiliatorAppDelegate GetUUID]; 
NSString *authURLString = [@"https://quizlet.com/authorize/?response_type=code&client_id=" stringByAppendingString:@"<myID>&scope=read"]; 
authURLString = [authURLString stringByAppendingString:@"&state="]; 
authURLString = [authURLString stringByAppendingString:quizletRandomString]; 
authURLString = [authURLString stringByAppendingString:@"&redirect_uri=Abiliator://after_oauth"]; 

NSLog(@"Authentication URL sent: %@", authURLString); 
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: authURLString]]; 

} 

Che funziona bene, come ho detto. L'app avvia Safari e l'utente deve confermare la richiesta immettendo l'id utente e la password e il server reindirizza nella mia app, che catturo nel metodo seguente, che quindi genera l'errore descritto.

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { 
if (!url) { return NO; } 
NSString *URLString = [url absoluteString]; 
NSLog(@"Received URL: %@", URLString); 
NSString *myURLQuery = [url query]; 
NSString *myAuthCode = [self getAuthorizationCodeFromURL:myURLQuery]; 
NSLog(@"Component1: %@", myAuthCode); 
NSString *authPasswd = @"myPasswd"; 
NSString *[email protected]"myUserName"; 

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.quizlet.com/oauth/token"]]; 

request.HTTPMethod = @"POST"; 

[request setValue:@"application/x-www-form-urlencoded; charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; 
[request setValue:@"Abiliator://after_oauth" forHTTPHeaderField:@"redirect_uri"]; 

// According to Quizlet API doc: You must set this (grant_type) to the string "authorization_code". 
[request setValue:@"authorization_code" forHTTPHeaderField:@"grant_type"]; 
[request setValue:myAuthCode forHTTPHeaderField:@"code"]; 

NSString *authStr = [NSString stringWithFormat:@"%@:%@", username, authPasswd]; 
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding]; 
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodedString]]; 
[request setValue:authValue forHTTPHeaderField:@"Authorization"]; 

NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 


return YES; } 

Qualsiasi aiuto apprezzato molto.

risposta

1

OAuth2 defines 4 ways per ottenere un token di accesso. Il più sicuro e complicato è il Authorization Code Grant utilizzato da Quizlet come descritto here.

L'autorizzazione Codice di Grant si compone di due fasi:

  • ottenere un codice di autorizzazione (l'utente si autentica qui al di fuori della vostra applicazione prima che il flusso passa di nuovo a voi tramite reindirizzamento)
  • modificare il codice di autorizzazione in un token di accesso

Hai fatto la prima chiamata a destra. Il problema con la seconda chiamata è che si inserisce il parametro grant_type nel posto sbagliato della richiesta. In questa linea ti trattano come un header HTTP:

[request setValue:@"authorization_code" forHTTPHeaderField:@"grant_type"]; 

E qui anche trattare il codice di autorizzazione come un header HTTP:

[request setValue:myAuthCode forHTTPHeaderField:@"code"]; 

Ma OAuth2 richiede di mettere entrambi nel corpo di la tua richiesta.Ecco un esempio di una corretta richiesta:

POST /oauth/token/ HTTP/1.1 
Content-Type: application/x-www-form-urlencoded;charset=UTF-8 
Content-Length: 999 
Authorization: Basic xxx 

grant_type=authorization_code&code=theCodeYouGotInTheFirstStep& 
scope=somescope&redirect_uri=theSameUriYouIncludedEarlier 

(La roba al di sotto della linea di vuoto è il corpo di richiesta)
(ho aggiunto l'interruzione di riga nel corpo solo per la leggibilità - non si deve includere in una richiesta)

Bonus risposta: si prega di tenere presente che OAuth2 è insicuro di default: se non si fa un po 'di lavoro extra, la vostra applicazione è vulnerabile agli attacchi Cross-Site Request Forgery come anche mentioned in the OAuth2 RFC. Per evitare che questo OAuth2 ti offre il parametro state. Devi generare un valore non immaginabile per il tuo state e includerlo nella prima richiesta. Non è necessario attivare la seconda richiesta, se il state restituito dal server non è lo stesso generato in precedenza.

+0

Grazie mille. Per quanto riguarda la sicurezza, passo il parametro state, vedi il primo codice nella mia domanda. Non ho ancora implementato il controllo di validazione. Per quanto riguarda il corpo, ho provato anche questo, lo stesso risultato. Ho aggiornato il mio post con lo snippet del corpo come ho implementato. – renesteg

+0

@renesteg nessun altro può vedere il tuo snippato perché la modifica è stata rifiutata, ma anche tu hai omesso il grant_type ma hai inserito invece le cose che appartengono all'intestazione come il tipo di contenuto e l'autorizzazione di base. Si prega di riprovare con la stringa che ho inserito nella mia risposta. –

+0

strano che le modifiche vengano rifiutate, in ogni caso, qui lo snippato che utilizzo per il metodo body: [bodyData appendData: [postMethodString dataUsingEncoding: NSUTF8StringEncoding]]; [bodyData appendData: [authCodeString dataUsingEncoding: NSUTF8StringEncoding]]; [bodyData appendData: [contentTypeString dataUsingEncoding: NSUTF8StringEncoding]]; [bodyData appendData: [basicAuthorizationString dataUsingEncoding: NSUTF8StringEncoding]]; e poi io uso [request setHTTPBody: bodyData]; dovrebbe andare bene, giusto? – renesteg

1

Potrebbe essere utile vedere il resto della vostra implementazione. Come stai ottenendo lo code? Inoltre, quali credenziali (authPasswd) stai utilizzando? Queste dovrebbero essere le tue app (al contrario di quelle dell'utente finale). Li ottieni in Dev Dashboard di Quizlet.

Note: this OAuth flow is not recommended for devices, as it requires secrets to be stored in the device. Using the implicit flow is, but I'm not sure Quizlet supports it.

+0

Grazie Eugenio per il vostro feedback. Sto utilizzando le credenziali per la mia app come specifica il quizlet: ho modificato il mio post per mostrare il primo passaggio del processo oauth 2. Nessun problema. L'unica cosa che non faccio ancora è confrontare la stringa casuale inviata per lo stato. Ma questo non dovrebbe essere un problema, poiché si tratta di una sicurezza aggiuntiva solo dal lato dell'app. Per quanto riguarda la tua nota: cosa intendi con flusso implicito? – renesteg

+0

Tutto sembra buono in superficie ... puoi inserire una traccia di rete per vedere cosa viene effettivamente inviato quando richiedi il token? "implicito" è solo un altro flusso in cui è possibile richiedere direttamente il token (senza scambio di codice). Vedi questo: http://stackoverflow.com/questions/16321455/oauth-2-0-difference-between-2-workflows-when-to-use-authorization-code-flow/16341985#16341985 –

+0

Questo è a 3 zampe flusso. La concessione implicita viene utilizzata quando il client è affidabile. Implicitamente taglia il flusso di inviare il codice di autenticazione al client, altrimenti un client deve presentare le sue credenziali e parametri insieme al codice di autenticazione per generare un token di accesso e una ragione principale è quella di convalidare se il codice di autenticazione viene presentato per acquistare lo stesso client per il quale è stato generato, (redirect_uri è obbligatorio qui). –

0

Invia i parametri oauth come carico utile. Non dovresti mandarli come intestazioni. Per esempio la richiesta dovrebbe sembra

POST /token 

Headers: 

Authorization: Basic R0cxSWJdHpINDVhang5Y0VlSUxxalBSOW5SU0NBWA== 

Content-Type: application/x-www-form-urlencoded 

Payload: 

grant_type=authorization_code&code=Wirr951e&scope=READ&redirect_uri=www.google.com 
Problemi correlati