21 Jan 2016

REST API using OAuth2

OAuth, REST 0 Comment

The intent is to implement OAuth2 provider protocol & secure appropriate rest api’s using OAuth2 token.

The generic need for any application would be to have some public API’s that can be accessed without any security, & some secured using token associated with clientId/secretKey & some secured using token associated with user credentials.

The following are the rest endpoints supporting OAuth2, which provide a token using different protocols, i.e Authorization Code Grant flow (1a,1b), Implicit Grant flow (2), Resource Owner Password Grant (3), Client Credentials Grant (4), Refresh Token Grant(5).

  • OAuth2 Rest End Points 
      1. [ GET] /oauth/authorize:
        • (1a) OAuth2 Authorization Code Grant
          parameters [ ?response_type=code&client_id=my-client&scope=read ]
        • (2) OAuth2 Implicit Grant
          parameters [ ?response_type=token&client_id=my-client&scope=read ]
      2. [ POST] /oauth/token:
            • (1b) OAuth2 Authorization Code Grant
              parameters [ ?grant_type=authorization_code&code=139R59&client_id=my-client ]
            • (3) OAuth2 Resource Owner Password Grant.
              parameters [ ?grant_type=password&client_id=..&client_secret=my-secret&username=aa&password=bb&scope=read ]
            • (4) OAuth2 Client Credentials Grant
              parameters [ ?grant_type=client_credentials&client_id=my-client&scope=read ]
            • (5) OAuth2 Refresh Token Grant
              parameters [ ?grant_type=refresh_token&refresh_token=22c3f395-690c-4838-a14f-3137e6802db1&client_id=my-client&scope=read ]

The following are the API endpoints we would like to support using the token provided above

    1. Public API’s
      1. [  GET] /api/v0/about
      2. [  GET] /api/v0/sample/about
    2. Secured access using a Client Token
      1. [  GET] /api/v0/sample/securedWithClientOAuth : Sample API secured with client token
      2. [POST] /api/v0/members/signup: Create a new User
      3. [POST] /api/v0/auth/login: Login using username/password credentials
    3. Secured access using User Token
      1. [  GET] /api/v0/sample/securedWithUserOAuth: Sample Secured with user token
      2. [  GET] /api/v0/members: Get list of members supports pagination ?filter=”field1=value,field2=v”&sort=”field2″&offset=15
      3. [  GET] /api/v0/members/{memberId}: Get information about a user
      4. [  PUT] /api/v0/members/{memberId}: update a user
      5. [  GET] /api/v0/auth/logout: logout the user associated with the token

In addition, we would want the api server to respond with the following standard HTTP Status responses across all api calls

  1. HTTP 200: Any successful REST api call along with its specific json data
  2. HTTP 400: Any api that results in validation errors like “invalid username”, “empty password” etc. along with json data with list of property errors
    “{ [propertyName:””, messageCode:””, message:””], [propertyName:””,messageCode:””].. }
  3. HTTP 404: Any non-existent REST api request using json along with json response of
    { messageCode:”api.notfound”, message:”locale based message desc”}
  4. HTTP 500: Any REST api request resulting in internal error along with json response of
    {messageCode:”api.internal.error”, message:”locale based message” }
  5. HTTP 403: Any REST api request resulting in forbidden
  6. HTTP 405: Any REST api request using invalid method i.e using GET instead of POST/PUT

Any REST API that supports pagination should respond data in the following format, with results containing the appropriate list items and accept “filter”,”offset”,”sort” & “order” as parameters.

{ 
      "from":10, 
        "to":15, 
"totalCount":100,
     results: [
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" },
       { prop1:"", prop2:"" }
     ]
}

Here is sample input/output for the api endpoints for successful responses

Input Output
[POST] /api/v0/members/signup: Create a new User
curl –X POST –d ‘{
“clientId”:”my-client”,
“username”:”abcdef”,
“password”:”123456″,
“email”:”abcd@ef.com”,
“firstName”:”abcd”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[POST] /api/v0/auth/login: Member Login
curl –X POST –d ‘{
“clientId”: “my-client”,
“username”: “abcdef”,
“password”: “123456”
}’
{“member”: {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
},
“token”: {
“access_token”: “7224..”,
“expires_in”: 43199,
“refresh_token”: “ebff..”,
“scope”: “read,write”,
“token_type”: “bearer”
} }
[  GET] /api/v0/members/{memberId}: Get Member
curl -H     “Authorization: Bearer 7224…” http://../api/v0/members/5 {
“description”: “”,
“email”: “abcd@ef.com”,
“firstName”: “abcd”,
“id”: 5,
“lastName”: “”,
“phone”: 0,
“socialAccounts”: []
}
[  PUT] /api/v0/members/{memberId}: Update Member
curl –X PUT –H “Authorization: Bearer 7224…”
-d { “id”: 5, “firstName”: “fname”, “lastName”: “lname”,”phone”: 0, “description”: “desc”} http://../api/v0/members/5
{
“description”: “desc”,
“email”: “abcd@ef.com”,
“firstName”: “fname”,
“id”: 5,
“lastName”: “lname”,
“phone”: 0,
“socialAccounts”: []
}


We will walk thru the implementation in the following sequence.

      1. Implement OAuth2 endpoints using OAuth2 Server library along with sample endpoints access controlled by client/user tokens
      2. Annotate your API with Swagger-UI
      3. Create API for Member Create/Read/Update
      4. Write Unit tests for Member Create/Read/Update
      5. Create API for Auth login/logout & Write Unit Tests

1. Create API for Member Create/Read/Update

Lets make a list of features that we want, just so it would guide us in our design.

  Feature
Login Domain
1a Ensure that password is getting encrypted while saving
1b We shouldn’t be able to create new Login with same username
1c We should have the ability to expire an account
1d We should have the ability to lock an account
Member Domain
2a Each member should have a unique UUID to identify them using URL
2b We cannot have two members with same email
2c A Member cannot exist without a Login
API / MemberController / create
3a Registration with an existing username should respond with 400
3b Registration with an existing email should respond with 400
3c Invalid email syntax should return 400
3d Successful registration should respond with 200 along with member info

Given the list of features, we will start off with the following ER Model

login-member-ermodel

If you are looking for PHP implementation, here is the link

If you are looking for Grails implementation, here is the link