Home

Awesome

About

I recently came across scala-oauth-provider which is a nice OAuth 2.0 provider implemented in scala .

There wasn't an example database structure to save the tokens, codes etc, so I tried to come up with one. I also needed to implement DataHandler.scala class to make it work with your own database tables.

I've used Playframework 2.2.1, PostgreSQL, play-slick, and scala-oauth-provider

There isn't any code for the authorization_code generation part in scala-oauth-provider. Therefore, this only deals with the returning access_token.

I'm a bit new to Scala, OAuth and Playframework so there might be problems :) Please feel free to fix them.

Database Schema

I've used postgresql with this example. Here is the database schema I've come up with:

CREATE TABLE "user"
(
  id serial NOT NULL,
  username character varying(100),
  email character varying(100),
  password character varying(100),
  CONSTRAINT pk_user PRIMARY KEY (id),
  CONSTRAINT ix_user_email_unique UNIQUE (email),
  CONSTRAINT ix_user_username_unique UNIQUE (username)
)


CREATE TABLE client
(
  id character varying(80) NOT NULL,
  secret character varying(80),
  redirect_uri character varying(2000),
  scope character varying(2000),
  CONSTRAINT pk_client PRIMARY KEY (id)
)

CREATE TABLE auth_code
(
  authorization_code character varying(40) NOT NULL,
  user_id integer NOT NULL,
  redirect_uri character varying(2000),
  created_at timestamp with time zone NOT NULL,
  scope character varying(1000),
  client_id character varying(80) NOT NULL,
  expires_in integer NOT NULL,
  CONSTRAINT pk_auth_code PRIMARY KEY (authorization_code),
  CONSTRAINT fk_auth_code_client_id FOREIGN KEY (client_id)
      REFERENCES client (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_auth_code_user_id_user_id FOREIGN KEY (user_id)
      REFERENCES "user" (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE access_token
(
  access_token character varying(60) NOT NULL,
  refresh_token character varying(60),
  user_id integer NOT NULL,
  client_id character varying(80) NOT NULL,
  scope character varying(2000),
  expires_in integer NOT NULL,
  created_at timestamp with time zone NOT NULL,
  CONSTRAINT pk_access_token PRIMARY KEY (access_token),
  CONSTRAINT fk_access_token_client_id FOREIGN KEY (client_id)
      REFERENCES client (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_access_token_user_id FOREIGN KEY (user_id)
      REFERENCES "user" (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE client_grant_type
(
  grant_type_id integer NOT NULL,
  client_id character varying(80) NOT NULL,
  CONSTRAINT pk_client_grant_type PRIMARY KEY (grant_type_id, client_id),
  CONSTRAINT fk_client_grant_type_client_id FOREIGN KEY (client_id)
      REFERENCES client (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_client_grant_type_grant_type_id FOREIGN KEY (grant_type_id)
      REFERENCES grant_type (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)


CREATE TABLE grant_type
(
  id integer NOT NULL,
  grant_type character varying NOT NULL,
  CONSTRAINT pk_grant_type PRIMARY KEY (id)
)


-- insert grant_types in grant_type configuration table
INSERT INTO grant_type (id, grant_type) VALUES (1, 'authorization_code')
INSERT INTO grant_type (id, grant_type) VALUES (2, 'client_credentials')
INSERT INTO grant_type (id, grant_type) VALUES (3, 'password')
INSERT INTO grant_type (id, grant_type) VALUES (4, 'refresh_token')


-- create sample user
INSERT INTO "user" (username, email, password) VALUES ('test_user', 'test_email', 'test_password')

-- create sample client
INSERT INTO client (id, secret, redirect_uri, scope) VALUES ('test_client_id', 'test_client_secret', 'http://xxx', 'read write update')

-- associate some grant_types to client
INSERT INTO client_grant_type (1, 'test_client_id')
INSERT INTO client_grant_type (2, 'test_client_id')
INSERT INTO client_grant_type (3, 'test_client_id')

Run

db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost:5432/oauth"
db.default.user=
db.default.password=""
cd path-to-scala-oauth-provider-example
play run

You should be able to make POST request like below and get the token result in json

Example OAuth access_token request using Password grant type: http://localhost:9000/oauth2/access_token?grant_type=password&client_id=test_client_id&client_secret=test_client_secret&username=test_user&password=test_password

Result:

{
    "token_type": "Bearer",
    "access_token": "MDEwNTBkNDgtNDhkNC00YmNhLWJiMjktMzVhMTJkMjMwNDBk",
    "expires_in": 3600,
    "refresh_token": "NzVmYjQ4ZDMtMjY3NS00NDA4LTkyZTgtNmNjOTNlNjRhNDZl"
}

Notes