Slide 1

Slide 1 text

RAILS AUTH - DIY AUTHENTICATION IN RAILS & API, DIY INSTEAD OF DEVISE Created by / Jesse Wolgamott @jwo

Slide 2

Slide 2 text

AUTHENTICATION & AUTHORIZATION Authentication: Knowing who you are Authorization: Granting access based on conditions

Slide 3

Slide 3 text

WHY NOT JUST USE DEVISE? Di cult to understand Di cult to customize Di cult to extend

Slide 4

Slide 4 text

GENERAL FLOW: 1. Request Page 2. Redirect to Sign in if not signed in 3. Sign in 4. Request Page 5. Now we view page!

Slide 5

Slide 5 text

REDIRECT TO SIGN IN IF NOT SIGNED IN c l a s s Y o u r C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r b e f o r e _ a c t i o n d o i f @ c u r r e n t _ u s e r . n i l ? r e d i r e c t _ t o s i g n _ i n _ p a t h , a l e r t : " P l e a s e S i g n I n " e n d e n d e n d

Slide 6

Slide 6 text

i f @ c u r r e n t _ u s e r . n i l ? So, we need something that sets @ c u r r e n t _ u s e r r e d i r e c t _ t o s i g n _ i n _ p a t h So, we need a s i g n _ i n _ p a t h

Slide 7

Slide 7 text

c l a s s A p p l i c a t i o n C o n t r o l l e r < A c t i o n C o n t r o l l e r : : B a s e p r o t e c t _ f r o m _ f o r g e r y w i t h : : e x c e p t i o n b e f o r e _ a c t i o n d o @ c u r r e n t _ u s e r = U s e r . f i n d _ b y i d : s e s s i o n [ : u s e r _ i d ] e n d e n d Before every single action is executed, Rails will look at the session and get the user_id It will try to nd a User by that id, so c u r r e n t _ u s e r may be nil Every action now has access to @ c u r r e n t _ u s e r

Slide 8

Slide 8 text

SessionController: c l a s s S e s s i o n s C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r d e f n e w e n d d e f c r e a t e e n d d e f d e l e t e e n d e n d Routes g e t ' s i g n _ i n ' = > ' s e s s i o n s # n e w ' , a s : : s i g n _ i n p o s t ' s i g n _ i n ' = > ' s e s s i o n s # c r e a t e ' d e l e t e ' s i g n _ i n ' = > ' s e s s i o n s # d e l e t e '

Slide 9

Slide 9 text

We'll end up at / s i g n _ i n if we are not already signed in. We need a form: < % = f o r m _ t a g d o % > < d i v > < % = l a b e l _ t a g : u s e r n a m e % > < % = t e x t _ f i e l d _ t a g : u s e r n a m e , p a r a m s [ : u s e r n a m e ] % > < / d i v > < d i v > < % = l a b e l _ t a g : p a s s w o r d % > < % = p a s s w o r d _ f i e l d _ t a g : p a s s w o r d , " " % > < / d i v > < d i v > < % = s u b m i t _ t a g " S i g n I n " , c l a s s : " b t n " % > < / d i v > < % e n d % >

Slide 10

Slide 10 text

Since we did not specify a location, Rails will use P O S T and the / s i g n _ i n path. That matches our Sessions#create. Yay!

Slide 11

Slide 11 text

Now we get to the core of the matter. How can we store a user's password, verify the user's password is correct, but never be able to reverse engineer the user's password?

Slide 12

Slide 12 text

BCRYPT

Slide 13

Slide 13 text

HAS_SECURE_PASSWORD c l a s s U s e r < A p p l i c a t i o n R e c o r d h a s _ s e c u r e _ p a s s w o r d v a l i d a t e s : u s e r n a m e , p r e s e n c e : t r u e , u n i q u e n e s s : t r u e e n d This requires us to have a database eld named p a s s w o r d _ d i g e s t .

Slide 14

Slide 14 text

THIS REQUIRES US TO HAVE A DATABASE FIELD NAMED P A S S W O R D _ D I G E S T .

Slide 15

Slide 15 text

when you set a user's password @ u s e r . p a s s w o r d = ' 1 2 3 4 5 ' , it will encrypt it into p a s s w o r d _ d i g e s t You cannot reverse engineer 1 2 3 4 5 You must give the password again to see if it's correct: @ u s e r . a u t h e n t i c a t e ( " 1 2 3 4 5 " ) = > # < U s e r i d = " 3 " . . . . / > @ u s e r . a u t h e n t i c a t e ( " 4 2 " ) = > n i l

Slide 16

Slide 16 text

c l a s s S e s s i o n s C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r d e f c r e a t e u s e r = U s e r . f i n d _ b y u s e r n a m e : p a r a m s [ : u s e r n a m e ] i f u s e r & & u s e r . a u t h e n t i c a t e ( p a r a m s [ : p a s s w o r d ] ) s e s s i o n [ : u s e r _ i d ] = u s e r . i d r e d i r e c t _ t o r o o t _ p a t h , n o t i c e : " S i g n e d i n ! " e l s e f l a s h . n o w [ : a l e r t ] = " S o m e t h i n g i s w r o n g w i t h y o u r u s e r n a m e a n d / o r p a s s w o r d " r e n d e r : n e w e n d e n d e n d

Slide 17

Slide 17 text

PROTIPS

Slide 18

Slide 18 text

c l a s s A p p l i c a t i o n C o n t r o l l e r < A c t i o n C o n t r o l l e r : : B a s e p r o t e c t _ f r o m _ f o r g e r y w i t h : : e x c e p t i o n b e f o r e _ a c t i o n d o @ c u r r e n t _ u s e r = U s e r . f i n d _ b y i d : s e s s i o n [ : u s e r _ i d ] e n d d e f a u t h e n t i c a t e _ u s e r ! u n l e s s @ c u r r e n t _ u s e r d o r e d i r e c t _ t o s i g n _ i n _ p a t h , n o t i c e : " P l e a s e S i g n I n " e n d e n d d e f c u r r e n t _ u s e r @ c u r r e n t _ u s e r e n d h e l p e r _ m e t h o d : c u r r e n t _ u s e r

Slide 19

Slide 19 text

Allow you to in your controllers: c l a s s Y o u r C o n t r o l l e r < A p p l i c a t i o n C o n t r o l l e r b e f o r e _ a c t i o n : a u t h e n t i c a t e _ u s e r ! e n d

Slide 20

Slide 20 text

Allows you to use in your ERB views: < % = i f u s e r _ s i g n e d _ i n ? % > H i < % = c u r r e n t _ u s e r % > . < % e l s e % > < % = l i n k _ t o ' S i g n U p ' , n e w _ u s e r _ p a t h % > < % e n d % >

Slide 21

Slide 21 text

SOOO BASICALLY, WE CREATED DEVISE. It's Secure It's rather easy to implement It's Easy to Extend and Customize

Slide 22

Slide 22 text

WHAT TO TAKE AWAY FOR BOTH DIY AND DEVISE @ c u r r e n t _ u s e r is not special. It's an ActiveRecord Object All the routes and controllers aren't special: you can customize then.

Slide 23

Slide 23 text

SECURING AN API

Slide 24

Slide 24 text

HAS_SECURE_TOKEN Requires you to have a t o k e n eld. c l a s s U s e r < A c t i v e R e c o r d : : B a s e h a s _ s e c u r e _ t o k e n e n d u s e r = U s e r . n e w u s e r . s a v e u s e r . t o k e n # = > " p X 2 7 z s M N 2 V i Q K t a 1 b G f L m V J E "

Slide 25

Slide 25 text

Each web request could then pass a token as an auth_token parameter. c l a s s A p i : : U s e r s C o n t r o l l e r < A p i C o n t r o l l e r b e f o r e _ a c t i o n d o @ c u r r e n t _ u s e r = U s e r . f i n d _ b y t o k e n : p a r a m s [ : a u t h _ t o k e n ] r e n d e r " A u t h T o k e n R e q u i r e d " , s t a t u s : 4 0 1 u n l e s s @ c u r r e n t _ u s e r e n d e n d

Slide 26

Slide 26 text

SIGNING IN TO API c l a s s A p i : : S e s s i o n s C o n t r o l l e r < A p i C o n t r o l l e r d e f c r e a t e @ c u r r e n t _ u s e r = U s e r . f i n d _ b y u s e r n a m e : p a r a m s [ : u s e r n a m e ] i f @ c u r r e n t _ u s e r & & @ c u r r e n t _ u s e r . a u t h e n t i c a t e ( p a r a m s [ : p a s s w o r d ] ) r e n d e r j s o n : { u s e r : @ c u r r e n t _ u s e r , a u t h _ t o k e n : @ c u r r e n t _ u s e r . t o k e n } , e l s e r e n d e r e r r o r s : [ " U s e r n a m e o r P a s s w o r d i s I n v a l i d " ] , s t a t u s : 4 2 2 e n d e n d e n d

Slide 27

Slide 27 text

DOWNSIDES There's only one token per user If regenerated, would sign out all phones/sessions/etc

Slide 28

Slide 28 text

DOORKEEPER DOORKEEPER IS AN OAUTH 2 PROVIDER FOR RAILS

Slide 29

Slide 29 text

ENABLING PASSWORD GRANT. / c o n f i g / i n i t i a l i z e r s / d o o r k e e p e r . r b D o o r k e e p e r . c o n f i g u r e d o o r m : a c t i v e _ r e c o r d r e s o u r c e _ o w n e r _ f r o m _ c r e d e n t i a l s d o U s e r . f i n d _ b y ( e m a i l : p a r a m s [ : u s e r n a m e ] ) . t r y ( : a u t h e n t i c a t e , p a r a m s [ : p a s s w o r d e n d a c c e s s _ t o k e n _ m e t h o d s : f r o m _ b e a r e r _ a u t h o r i z a t i o n , : f r o m _ a c c e s s _ t o k e n _ p a r a m g r a n t _ f l o w s % w ( p a s s w o r d ) e n d D o o r k e e p e r . c o n f i g u r a t i o n . t o k e n _ g r a n t _ t y p e s < < " p a s s w o r d "

Slide 30

Slide 30 text

from_bearer_authorization (header): ' A u t h o r i z a t i o n ' : ' B e a r e r T O K E N H E R E ' from_access_token_param : ? a c c e s s _ t o k e n = T O K E N H E R E

Slide 31

Slide 31 text

IN YOUR CONTROLLER c l a s s A p i : : B o o k s C o n t r o l l e r < A p i : : V 1 : : A p i C o n t r o l l e r b e f o r e _ a c t i o n : d o o r k e e p e r _ a u t h o r i z e ! d e f i n d e x r e n d e r j s o n : { b o o k s : c u r r e n t _ u s e r . b o o k s } e n d p r i v a t e d e f c u r r e n t _ u s e r U s e r . f i n d ( d o o r k e e p e r _ t o k e n . r e s o u r c e _ o w n e r _ i d ) i f d o o r k e e p e r _ t o k e n e n d e n d

Slide 32

Slide 32 text

1. Already have User with secure password 2. add to gem le d o o r k e e p e r 3. b u n d l e i n s t a l l 4. Add le c o n f i g / i n i t i a l i z e r s / d o o r k e e p e r . r b 5. Add to routes: u s e _ d o o r k e e p e r 6. r a i l s g e n e r a t e d o o r k e e p e r : m i g r a t i o n 7. r a i l s d b : m i g r a t e

Slide 33

Slide 33 text

SIGNING IN POST JSON to / o a u t h / t o k e n { " g r a n t _ t y p e " : " p a s s w o r d " , " u s e r n a m e " : " j w o " , " p a s s w o r d " : " 1 2 3 4 5 " } Result will have { " a u t h _ t o k e n " : " e e b d a d d b 2 c 2 d e 2 8 1 7 d b d 6 b e b e 0 6 b 0 a 7 f f a 3 4 f f d 3 8 a d e b 7 d 0 " , " e x p i r e s " : 1 2 3 4 5 6 7 8 9 0 }

Slide 34

Slide 34 text

BENEFITS OF DOORKEEPER 1. Multiple signing per account 2. Can be expanded later 3. Fits into Grape

Slide 35

Slide 35 text

LIVE DEMO WE'LL DO IT LIVE

Slide 36

Slide 36 text

Links: / t: @jwo g: @jwo Slides Code (Before and After)