본문 바로가기

프로그램/iPhone

oauth로 twitter api 인증하고 api 사용하기


OAuth를 사용해서 인증을 받는 과정은 다음과 같다.


  1. 일단 twitter 에 자신의 application을 등록한다http://twitter.com/oauth_clients
    여기서 얻게 되는 consumer key와 secret을 잘 저장해둔다.

  2. Oauth 인증을 도와주는 objective-c 라이브러리인 OAuthConsumer를 프로젝트에 넣는다.
    원본의 경우 조금의 손을 봐야하므로 http://crizin.net/entry/Using-OAuth-Consumer-Library-In-iPhone 에서 이미 고쳐진 버젼을 구한다.

  3. Consumer Key와 Secret을 이용해서 request_token을 얻어온다.

    OAConsumer *consumer = [[OAConsumer allocinitWithKey:CONSUMER_KEY secret:CONSUMER_SECRET

    NSURL *url = [[NSURL allocinitWithString:REQUEST_TOKEN_URL]

    OAMutableURLRequest *request = [[OAMutableURLRequest allocinitWithURL:url consumer:consumer

    token:nil

    realm:SERVICE_URL

    signatureProvider:nil];

    [request setOAuthParameterName:@"oauth_callback" withValue:@"oob"];

    OADataFetcher *fetcher = [[OADataFetcher allocinit];

    [fetcher fetchDataWithRequest:request

    delegate:self

    didFinishSelector:@selector(requestTokenTicket:didFinishWithData:)

    didFailSelector:@selector(requestTokenTicket:didFailWithError:)];


  1. 얻어온 request_token을 이용하여 Login하는 Page 얻어온다.

    NSString *authorizeURL = [[NSString alloc
    initWithFormat:@"%@?oauth_token=%@",

    AUTHORIZE_URL,

    [oaRequestToken.key URLEncodedString]];


    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:authorizeURL]];

    [authorizeURL release];


    NSURLResponse *response;

    NSError *error;

    NSData *urlData = [NSURLConnection sendSynchronousRequest:urlRequest

    returningResponse:&response error:&error];


  1. login page를 파싱하여 POST를 구성하고 oauth_pin값을 얻어온다.


    아이폰에서는 특별한 입력 폼을 매번 사용해서 인증을 받을 수 없기 때문에,

    (한번 입력한 값으로 계속 인증을 하기 위해서이 페이지를 자동으로 처리해주는 것이 필요하다

    이 페이지 소스를 보면 POST방식으로 form에서 데이터를 건네주는 것을 알 수 있으므로,

    hidden처리 된 데이터를 가져와 자동으로 POST로 보내주도록 한다.


    NSString *post =[[NSString alloc]

    initWithFormat:@"oauth_token=%@&authenicity_token=%@&session[username_or_email]=%@&session[password]=%@",

    [oaRequestToken.key URLEncodedString],

    authenicity_token,

    [@"ID" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],

    [@"Password" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];


    NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

    [post release];


    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

    NSMutableURLRequest *request = [[[NSMutableURLRequest allocinitautorelease];

    [request setURL:[NSURL URLWithString:AUTHORIZE_URL]];

    [request setHTTPMethod:@"POST"];

    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

    [request setHTTPBody:postData];


    urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

    NSString *data=[[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];


    위에서 볼 수 있듯이 필요한 데이터는 네가지이다첨에 얻어온 request_token.key 값과

    페이지에서 파싱하면 얻을 수 있는 authenicity_token, 그리고 id, password이다.

    위의 이름을 잘 지켜주어야 제대로 인증이 되므로 유의해야한다.

    또한 POST방식으로 보내는 절차를 잘 준수해줘야 twitter가 뺀찌 놓지 않는다.

    얻어온 데이터는 Pin값을 포함한 웹페이지 이므로 PIN값 또한 파싱해주어야 한다.


  1. 얻어온 PIN값을 이용하여 access_token을 얻어온다.

    OAConsumer *consumer = [[OAConsumer allocinitWithKey:CONSUMER_KEY secret:CONSUMER_SECRET];

    NSURL *url = [[NSURL allocinitWithString:ACCESS_TOKEN_URL];

    OAMutableURLRequest *request = [[OAMutableURLRequest allocinitWithURL:url

    consumer:consumer token:self.oaRequestToken

    realm:SERVICE_URL

    signatureProvider:nil];


    [request setOAuthParameterName:@"oauth_verifier" withValue:[NSString stringWithFormat:@"%@",oauthPIN]];

    OADataFetcher *fetcher = [[OADataFetcher allocinit];


    [fetcher fetchDataWithRequest:request

    delegate:self

    didFinishSelector:@selector(accessTokenTicket:didFinishWithData:)

    didFailSelector:@selector(accessTokenTicket:didFailWithError:)];


  1. 얻어온 access_token을 이용해 twitter의 POST api를 사용한다.

    이 부분이 가장 헷갈린 부분이었는데의외로 해결은 간단하다.
    OAuthConsumer
    가 제공하는 OAMutableURLRequest와 POST방식을 적절하게 섞어주면 가능하다.
    원래 Twitter의 API는 POST방식만을 지원하는데,

    OAuth의 설명 페이지는 Get방식으로 진행되어 있다. (http://oauth.net/core/1.0a/)
    따라서 그 안의 내용과는 조금 다른 방식으로 진행해주어야 한다.
    POST
    와 Get의 가장 큰 차이는 argument가 주소에 있는가 없는가이다.
    POST
    방식이어야 하므로 일단 OAuth의 Document에 있는 것 처럼 Signature에 부가적인 인자

    만일 twitter의 update api를 생각하면 status )를 넣으면 안된다.
    그 외의 auth와 관련있는 인자들은 signature에 포함된다.

    twitter
    의 글쓰기는 update.json?status=”blabla”로 이루어지므로 이를 예를 들면 다음과 같다.

    OAConsumer *consumer = [[OAConsumer allocinitWithKey:CONSUMER_KEY

    secret:CONSUMER_SECRET];


    NSURL *url = [[NSURL allocinitWithString:UPDATE_URL];

    OAMutableURLRequest *request = [[OAMutableURLRequest allocinitWithURL:url

    consumer:consumer

    token:self.oaAccessToken

    realm:SERVICE_URL

    signatureProvider:nil];


    NSString *post =[[NSString allocinitWithFormat:@"status=%@",tweetContents];

    NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

    [post release];

    [request setHTTPMethod:@"POST"];

    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];

    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

    [request setHTTPBody:postData];


    OADataFetcher *fetcher = [[OADataFetcher allocinit];

    [fetcher fetchDataWithRequest:request

    delegate:self

    didFinishSelector:@selector(updateStatusTicket:didFinishWithData:)

    didFailSelector:@selector(updateStatusTicket:didFailWithError:)];


    setValue와 setHTTPBody 부분은 실제 signature 제작에 쓰이지 않는다. 따라서 signature에서 status는 빠지게 되고,

    여타 POST에 필요한 데이터는 제거되는 것이다.

    자세한 signature 제작 과정이 궁금하면 위 링크된 oauth설명 페이지 혹은 OAMutableURLRequest의 prepare부분을 참조하면 된다.