'Tool/OAuth'에 해당하는 글 5건

 

Oauth2.0 에서 Token 발급에 필요한 ClientId 와 SecretKey 생성하기.

 

 

ClientId

 

  • 일반적으로 길이 16~32자 16진수 문자열로 생성.
  • 모든 클라이언트에서 고유함.

 

SecretKey

 

  • 일반적으로 길이 32~64자 16진수 문자열로 생성.
  • TimeStamp / UUID 라이브러리 등은 지양.
  • 일반 암호와 동일하므로 DB 에는 암호화 되거나 해시된 버전으로 저장.

 

ClientId ex)

 

Foursquare: ZYDPLLBWSK3MVQJSIYHB1OR2JXCY0X2C5UJ2QAR2MAAIT5Q
Github: 6779ef20e75817b79602
Google: 292085223830.apps.googleusercontent.com
Instagram: f2a1ed52710d4533bde25be6da03b6e3
SoundCloud: 269d98e4922fb3895e9ae2108cbb5064
Windows Live: 00000000400ECB04
Okta: 0oa2hl2inow5Uqc6c357

 

 

Client Id / Secret Key 생성

 

commons-lang3 의 RandomStringUtils 를 사용하여 특정 길이의 랜덤한 문자열을 생성할 수 있다.

 

dependencies {
    implementation 'org.apache.commons:commons-lang3:3.12.0'
}

...

RandomStringUtils.randomAlphanumeric(32));  
// 1JhGTHmGlCP037aATyJzph983FRl5r14
RandomStringUtils.randomAlphanumeric(64));  
// 84ldr2jaagfMiIwzj2wFnaPxXBV2Yc9WC1AbJPaugEj5qHSWHkPjt2HInLdlzV7S

 

spring-security 를 사용할 경우, SecretKey 를 한번 더 암호화 하기 위해 BCryptPasswordEncoder 클래스를 사용한다.

 

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodeKey = passwordEncoder.encode(secretKey);

 

PasswordEncoder.encode 는 항상 랜덤키를 생성하기 때문에 인코딩된 결과끼리의 비교는 불가능하지만, secretKey 와 encodeKey 의 비교는 가능하다.

 

if (passwordEncoder.matches(secretKey, encodeKey)) {
    System.out.println("matching~");
}

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

SNS crawling

Tool/OAuth 2017. 12. 19. 00:29

대부분의 SNS 마다 로그인/글쓰기/글읽기 등을 위한 API 를 제공한다. 또한 각 SNS 에서 제공하는 여러 토큰 유형을 각 서비스에 맞게 활용하여야 한다. 흔히 게임이나 웹서비스에서 이미 가입된 SNS 계정으로 로그인하는 방식이 일반적인 SNS 사용자 인증 방식이다. 각 사용자를 로그인 시켜, 해당 사용자의 정보를 가져오는 것이다. 예를 들어, A 라는 서비스를 사용시 페이스북 계정으로 로그인하면, 페이스북으로부터 로그인한(인증된) 사용자의 정보가 A 서비스로 전달되는, OAuth 라는 인증 방식을 주로 사용한다. 즉, 사용자의 데이터(개인 정보 등) 를 읽어올 때, 사용자 액세스 토큰을 생성하면 된다.


그렇다면 내 사이트에 뿔뿔히 흩어진 SNS 의 내 게시물들을 표시하고 싶다면 어떻게 해야 할까. 위 사용자 액세스 토큰을 취득하기 위해, 매번 각각의 SNS 로그인 화면에서 id/pw 를 입력할 수는 없다. 이 때는 각 SNS 의 개발자 모드에서 앱을 생성하고 발급된 client_id / client_secret 를 전달하는 식으로 앱 액세스 토큰을 발급받아 사용하면 된다. 아래는 SNS crawling 을 위해 로그인을 하지 않고 각 계정의 데이터를 가져온 Java 코드의 예이다. (without redirect_url)



Facebook


서비스가 Spring 기반이라 Spring Social Facebook 을 사용해 보려 했으나, 사용자 인증 방식 밖에 안된다. 즉, 로그인 인증을 거치게 된다. 페이스북 API 버전도 너무 오래된 걸 사용하고 있고... 다음처럼 페이스북 그래프 API 를 사용하여 앱 액세스 토큰을 발급받는다.


GET /oauth/access_token
    ?client_id={app-id}
    &client_secret={app-secret}
    &grant_type=client_credentials
Host: graph.facebook.com
cs


데이터를 읽어오거나 할 때는, 각 파라미터 끝에 access_token 만 추가하면 된다.


GET /v2.11/me/feed?access_token={access_token}
Host: graph.facebook.com
cs


반환된 데이터에서 paging.next 가 없어질 때까지 계속 돌리면 모든 피드 데이터를 가져올 수 있다.



Twitter


트위터는 조금 더 까다롭다. client_id / client_secret 를 전달하는데 Base64 인코딩을 하여 Authorization 헤더에 담아 POST 방식으로 보낸다. bearer access_token 이 반환되며, 이 토큰을 API 요청시 Authorization 헤더에 담아 요청하면 된다. 이 과정을 간단하게 해결해주는 라이브러리를 twitter4j 에서 제공한다.


gradle 등의 빌드 툴로 twitter4j 를 가져온다.


compile group: 'org.twitter4j', name: 'twitter4j-http2-support', version: '4.0.6'
cs


그리고 토큰을 가져와 twitter 인스턴스를 만드는 코드이다. consumerKey 와 consumerSecret 만 넣으면 된다.


ConfigurationBuilder cb = new ConfigurationBuilder();
 
cb.setApplicationOnlyAuthEnabled(true);
cb.setOAuthConsumerKey(consumerKey);
cb.setOAuthConsumerSecret(consumerSecret);
 
try {
    OAuth2Token token = new TwitterFactory(cb.build()).getInstance().getOAuth2Token();
 
    cb = new ConfigurationBuilder();
    cb.setApplicationOnlyAuthEnabled(true);
    cb.setOAuthConsumerKey(consumerKey);
    cb.setOAuthConsumerSecret(consumerSecret);
    cb.setOAuth2TokenType(token.getTokenType());
    cb.setOAuth2AccessToken(token.getAccessToken());
 
    twitter = new TwitterFactory(cb.build()).getInstance();
catch (TwitterException e) {
    e.printStackTrace();
}
cs


반환된 데이터에서 page + 1 로 반환되는 데이터가 없을 때까지 계속 돌리면 모든 트윗을 가져올 수 있다.



Youtube


유투브도 OAuth 2.0 기반의 인증 방식을 사용하지만 약간의 추가 설정이 필요하다. 우선 유투브 API 를 사용하려면 구글 개발자 콘솔에서 라이브러리의 YouTube Data API v3 을 활성화 해야 한다. 그리고 사용자 인증 정보 메뉴에서 서비스 계정(Service account) 키를 생성하고, 비공개 키가 포함된 정보를 json 파일로 다운받아야 한다. 서비스 계정은 사용자 정보에 액세스하지 않는 API를 호출하는 애플리케이션에서 사용된다.


표준 라이브러리를 사용하여 구현해 본다.


compile group: 'com.google.apis', name: 'google-api-services-youtube', version: 'v3-rev188-1.23.0'
compile group: 'com.google.oauth-client', name: 'google-oauth-client-java6', version: '1.23.0'
compile group: 'com.google.oauth-client', name: 'google-oauth-client-jetty', version: '1.23.0'
cs


그리고 YouTube 인스턴스를 만들어 데이터를 가져온다.


public static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
public static final JsonFactory JSON_FACTORY = new JacksonFactory();
 
private YouTube youtube;
 
public YoutubeService() {
    List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube.readonly");
 
    GoogleCredential credential = null;
    try {
        credential = GoogleCredential.fromStream(YoutubeService.class
                .getResourceAsStream("/service-account.json")).createScoped(scopes);
    } catch (IOException e) {
        e.printStackTrace();
    }
 
    // This object is used to make YouTube Data API requests.
    youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
            .setApplicationName("oops4u").build();
}
cs


반환된 데이터에서 nextPageToken 이 없어질 때까지 계속 돌리면 모든 동영상 데이터를 가져올 수 있다.



Instagram


인스타그램은... 현재 인증 및 권한 부여를 위해 OAuth 2.0 을 사용중이나, 권한 부여 과정에서 return URL 을 필요로 하고 있으며 다른 대안은 없다. 그러나... 이걸 또 해낸 사람들이 있네.


https://github.com/postaddictme/instagram-java-scraper

https://jitpack.io/#postaddictme/instagram-java-scraper/0.3.0


인증이 필요없는 장점. 옛날 endpoint 를 가지고 있긴 한데 막힐 때까지는 쓸만할 듯.


OkHttpClient okHttpClient = new OkHttpClient();
Instagram instagram = new Instagram(okHttpClient);
cs


계정 게시물 수 가져오고 그만큼 미디어 겟하면 끝.



-----------------------------------------------------------------------------------


2018년 10월 - instagram 정책변경으로 위 api 막힘 - instagram4j 대체.


// https://mvnrepository.com/artifact/org.brunocvcunha.instagram4j/instagram4j
compile ('org.brunocvcunha.instagram4j:instagram4j:1.7') {
    exclude group: 'org.bytedeco'
}
cs



WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

OAuth2 Server for PHP

Tool/OAuth 2016. 3. 1. 23:09

OAuth2 서버를 만들기 위해 bshaffer 의 oauth2-server-php 코드를 사용한다.

https://github.com/bshaffer



요구사항

PHP 5.3.9 이상



설치

1
2
3
4
# git
$ git clone https://github.com/bshaffer/oauth2-server-php.git
# composer
$ composer.phar require bshaffer/oauth2-server-php "~1.8"
cs

(구조는 약간 틀리지만 composer 로 설치하여 테스트 하였다.)



Table 생성

* MySQL / SQLite / PostgreSQL / MS SQL Server

1
2
3
4
5
6
7
CREATE TABLE oauth_clients (client_id VARCHAR(80NOT NULL, client_secret VARCHAR(80), redirect_uri VARCHAR(2000NOT NULL, grant_types VARCHAR(80), scope VARCHAR(100), user_id VARCHAR(80), CONSTRAINT clients_client_id_pk PRIMARY KEY (client_id));
CREATE TABLE oauth_access_tokens (access_token VARCHAR(40NOT NULL, client_id VARCHAR(80NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT access_token_pk PRIMARY KEY (access_token));
CREATE TABLE oauth_authorization_codes (authorization_code VARCHAR(40NOT NULL, client_id VARCHAR(80NOT NULL, user_id VARCHAR(255), redirect_uri VARCHAR(2000), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT auth_code_pk PRIMARY KEY (authorization_code));
CREATE TABLE oauth_refresh_tokens (refresh_token VARCHAR(40NOT NULL, client_id VARCHAR(80NOT NULL, user_id VARCHAR(255), expires TIMESTAMP NOT NULL, scope VARCHAR(2000), CONSTRAINT refresh_token_pk PRIMARY KEY (refresh_token));
CREATE TABLE oauth_users (username VARCHAR(255NOT NULL, password VARCHAR(2000), first_name VARCHAR(255), last_name VARCHAR(255), CONSTRAINT username_pk PRIMARY KEY (username));
CREATE TABLE oauth_scopes (scope TEXT, is_default BOOLEAN);
CREATE TABLE oauth_jwt (client_id VARCHAR(80NOT NULL, subject VARCHAR(80), public_key VARCHAR(2000), CONSTRAINT jwt_client_id_pk PRIMARY KEY (client_id));
cs



기본 동작 구현


OAuth2 server Bootstrap

모든 엔드포인트로부터 사용될 OAuth2 server 객체를 생성하고 설정하는 부트스트랩 파일을 생성한다. (server.php)


Token Controller

클라이언트에게 OAuth2.0 토큰을 반환하는 토큰 컨트롤러 파일을 생성한다. (token.php)

임의로 DB 에 클라이언트 정보를 하나 삽입하고 curl 로 HTTP 요청을 하여 토큰 생성을 테스트할 수 있다.


DB 삽입

1
INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES ("testclient""testpass""http://fake/");
cs


토큰 요청

1
2
$ curl -su testclient:testpass http://localhost/token.php -'grant_type=client_credentials'
{"access_token":"2577de35659f485b382d680edbba95356b595475","expires_in":3600,"token_type":"Bearer","scope":null}
cs

(호스트명은 localhost 라고 가정한다.)


Resource Controller

위에 생성된 토큰을 이용하여, 앞으로 만들 리소스나 API 에서 토큰의 유효성을 체크할 수 있다. (resource.php)


1
2
$ curl http://localhost/resource.php -'access_token=2577de35659f485b382d680edbba95356b595475'
{"success":true,"message":"You accessed my APIs!"}
cs


Authorize Controller

권한 부여 컨트롤러는 OAuth2 의 핵심 기능(killer feature)이며, 써드파티 어플리케이션에 사용자 권한을 부여할 수 있게 한다.

처음 토큰 컨트롤러 예제에서는 Access Token 이 즉시 발급되었지만, 권한 부여 컨트롤러는 사용자가 요청 권한을 가졌을 때 토큰을 발생하는데 사용한다. (authorize.php)


http://localhost/authorize.php?response_type=code&client_id=testclient&state=xyz


이 URL 을 브라우저에 입력하면 해당 해당 client_id 에게 권한을 부여할 것인지를 묻는 프롬프트 폼이 보여진다.

'예'를 클릭하면 발급된 Authorization Code 를 확인할 수 있다.


SUCCESS! Authorization Code: 097e3c941d91a84861fef771c025cbb365dff010


이제 미리 만들어놓은 토큰 컨트롤러에서 Authorization Code 로 Access Token 을 발급받을 수 있다.

1
2
$ curl -u testclient:testpass http://localhost/token.php -'grant_type=authorization_code&code=097e3c941d91a84861fef771c025cbb365dff010'
{"access_token":"1bde0a7785f78eaddcd3e4555ca382e884d9ad4f","expires_in":3600,"token_type":"Bearer","scope":null,"refresh_token":"c8d988fdcf8707f5e8f728a86aa0e49d3109b9b0"}
cs

Authorization Code 는 발급 후 30초 뒤에 만료된다.


Associating Local Users With Access Tokens

사용자 권한을 인증하고 access token 을 발급하면, 토큰을 사용한 사용자가 누구인지 알고 싶을 것이다.

handleAuthorizeRequest 메소드의 파라미터에 user_id 를 사용하면 사용자를 알 수 있다.


1
2
3
<?
$userid = 1234// A value on your server that identifies the user
$server->handleAuthorizeRequest($request$response$is_authorized$userid);
cs


사용자 ID 는 access token 과 함께 DB 에 저장될 것이다.

이 토큰이 클라이언트로부터 사용되면 할당된 ID 를 검색할 수 있다.


1
2
3
4
5
6
7
8
<?
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
    $server->getResponse()->send();
    die;
}
 
$token = $server->getAccessTokenData(OAuth2\Request::createFromGlobals());
echo "User ID associated with this token is {$token['user_id']}";
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

Twitter OAuth

Tool/OAuth 2015. 12. 30. 08:13

현재 트위터의 API v1.1 의 인증 프로토콜은 OAuth 1.0A 를 사용 중이다.

OAuth 는 2010년 IETF OAuth 워킹그룹에 의해 IETF 표준 프로토콜로 발표 되었고, 세계 많은 인터넷 서비스 기업들에서 표준 인증 방식으로 OAuth 를 사용하고 있다. 

OAuth 인증 방식을 이용하면 이 인증을 공유하는 어플리케이션(웹, 모바일, 데스크탑)끼리는 별도의 인증이 필요 없다.

현재 OAuth2.0 버전까지 나와 있고 2.0버전은 1.0버전과 호환되지는 않지만 더 많은 장점이 있다.



OAuth 1.0A


OAuth 에 등장하는 출연진 들이다.


  • service provider (서비스 제공자) : 트위터처럼 OAuth 인증 방식을 이용하여 API 등을 제공하는 웹 어플리케이션
  • consumer (소비자) : 서비스 제공자의 API 를 이용할 어플리케이션
  • user (사용자) : 서비스 제공자와 소비자에 계정을 가지고 있는 사용자


OAuth 의 목적은 사용자가 소비자 어플리케이션에서 서비스 제공자의 어플리케이션의 권한인 Access Token 을 획득하는 것이다.

이를 위한 전제 조건으로는


  • 소비자가 서비스 제공자에 가입하여 인증에 필요한 consumer keyconsumer secret 를 획득해야 한다.
  • 사용자는 서비스 제공자에 가입이 되어 있어야 한다.




이제 위 그림을 살펴보면 다음과 같다.


  1. 사용자가 서비스 제공자 권한이 필요한 행위를 하려고 하면 소바자가 서비스 제공자에게 Request Token 을 요청한다.
    이 Request Token 은 사용자 접근 권한을 인증 받기 위해 필요하며 뒤에 Access Token 과 교환한다.
  2. 서비스 제공자는 consumer key 와 서명등을 확인하여 소비자에게 Request Token 을 발급한다.
  3. 소비자는 서비스 제공자로 사용자를 보내 로그인 및 접근 권한 요청 등을 승인하게 한다.
  4. 소비자가 접근 권한을 승인했으면 다시 소비자로 돌려보낸다. 만약 접근 권한을 승인하지 않았으면 다시 A 로 돌아간다.
  5. 소비자는 Request Token 을 포함하여 서비스 제공자에게 Access Token 을 요청한다.
  6. 서비스 제공자는 Access Token 을 발급한다.
  7. 소비자는 발급된 사용자 Access Token 으로 서비스 제공자의 API 를 이용한다.  


위 단계에서 서비스 제공자는 Request Token 과 Access Token 만 발급 해준다.

소비자는  Request Token 과 Access Token 요청, 사용자 접근 권한 요청을 한다.

사용자는 서비스 제공자에 로그인 / 사용자 접근 권한 승인만 한다.


OAuth 1.0A 를 채택한 서비스들의 방식은 모두 동일하다.

트위터도 마찬가지로 Access Token 을 획득해야만 이용 가능한 API 들이 대부분이다.

또한 위에서 처럼 서비스 제공자 / 소비자 / 사용자의 조합에서 사용자는 전혀 관련없는 Applicatoin-only 인증의 경우 사용자 인증은 필요없다.

어플리케이션용 인증이 필요한 API 의 경우 기간내 호출 횟수에 제한을 두는 것이 특징이다.



OAuth1.0A Document - http://oauth.net/core/1.0a/



WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

twitter API

Tool/OAuth 2015. 12. 28. 23:52

REST APIs

 

요즘은 웹이든 앱이든 페이스북이나 트위터, 구글 등의 SNS 계정으로 회원가입을 받는 경우가 많다.
따로 회원가입 양식을 요구하지 않으니 사용자 입장에서도 좋고, SNS 연동이나 홍보가 편리하므로 서비스 입장에서도 좋다.
회원가입을 하지 않고도 타 사이트에서 SNS 계정의 권한으로 서비스를 이용하는 것은 각 SNS에서 제공하는 API / SDK 덕분이다.

 

예를 들어, A 쇼핑몰에 트위터 계정으로 로그인 한 후에 마이페이지 등에서 내 트위터 친구 목록 불러오기를 할 수 있다.
트위터에 방문하지 않고 트위터 데이터를 읽어올 수 있는 것은 A 쇼핑몰에서 트위터가 제공하는 API 를 사용하기 때문이다.
twitter API 를 사용하면 새 트윗, 프로필이나 팔로워 등 트위터 상의 데이터들을 읽어오거나 작성할 수 있다.

 

A 쇼핑몰에서 twitter API 를 사용하여 B 사용자의 권한으로 개인정보를 가져올 수 있었던 것은 A 쇼핑몰이 트위터로부터 인증을 받았기 때문이다.
대단한 인증이 아니다. 트위터 개발자 사이트(https://dev.twitter.com/)에 가입을 하고 [Manager Your Apps] 에서 프로젝트(App)를 새로 만들면,
예를 들어, A 쇼핑몰 전용 프로젝트(App)를 만들면 그 프로젝트에 대한 고유 키가 발급된다.


- Consumer Key
- Consumer Secret

그리고 A 쇼핑몰에서 이 키들을 사용하여 API 를 요청하면, 트위터에서 '아~ A 쇼핑몰에서 API 를 요청하는구나~' 라고 인식하고 요청을 허용한다.

 


REQUEST URL

 

twitter API 는 restful 방식이다.
REST API. 즉, URL 과 HTTP 메소드를 이용하여 결과를 얻는 방식이다.
예를 들어, 로그인한 사용자의 친구 목록을 불러오는 API 를 사용해 보면,

 

1
2
3
4
5
6
GET https://api.twitter.com/1.1/friends/list.json
 
"errors": {
    "code"215
    "message""Bad Authentication data."
}
cs


인증 오류이다.
단지 저 URL 을 링크 걸어놓는다고 해서 트위터가 모든 요청을 허용하지는 않는다. API 마다 다르긴 하지만

 

Requires authentication? Yes

 

라고 리소스 정보에 쓰여 있다면 이 API 는 트위터가 인식할 수 있도록 요청 헤더에 인증 정보를 함께 넘겨야 올바른 결과값을 받을 수 있다.
API 로 접근하려는 소비자(Consumer) 가 누구인지, 어떤 사용자의 Token 으로 정보를 얻으려 하는지를 트위터가 정해놓은 방식대로 요청 헤더에 담아 전달해야 한다.

 

이런식의 Flow 가 바로 OAuth 라는 표준 인증 방식이다.
트위터는 이 OAuth  인증 방식으로 Consumer(A 쇼핑몰)들에게 API 를 제공한다.

 

 

 


WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,