Authenticate and authorize API with Apigility by Enrico Zimuel (@ezimuel) Software Engineer Apigility and ZF2 Team
About me Enrico Zimuel (@ezimuel) Software Engineer since 1996 PHP Engineer at Zend Technologies Member of Apigility and Zend Framework team International speaker, author of articles and books about applied cryptography and web programming Co-founder PUG Torino (Italy) http://torino.grusp.org
Apigility API builder for PHP applications RESTful/RPC JSON (HAL) as default format Error handling (HTTP problem) Content negotiation Versioning (via URI and Accept header) Filtering and validation Authentication Documentation Built in Zend Framework 2 (set of modules)
Release status We released Apigility ver. 0.8.0 the 20 Dec. 2013 This version includes all the Apigility features except for API Documentation We changed the minimum supported PHP version to 5.4.8 Goal: release 1.0 in the 1 st quarter of 2014 More information on http://www.apigility.org
Authentication Apigility offers the following API authentications: HTTP Basic and Digest (RFC 2617) OAuth2 (RFC 6749) Using Apigility we can authenticate specific API service (URL) and HTTP methods
HTTP Basic auth Authentication based on username and password Request of authentication, server header: WWW-Authenticate: Basic realm="insert realm" Client header: Authorizazion: Basic Base64(username:password) Example: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Basic File resolver Apigility supports File resolver and Apache (htpasswd) for storing username and password File format: <username>:<realm>:<password>\n Security note: the <password> is in plaintext!
HTTP Digest auth Authentication based on username and password Request of authentication, server header example: WWW-Authenticate: Digest realm="insert realm", qop="auth", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Client header example Authorization: Digest username="insert username", realm="insert realm", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="uri of the request", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41"
Digest response algorithm More information: http://en.wikipedia.org/wiki/digest_access_authentication
Digest File resolver Apigility supports File resolver and Apache (htpasswd) for storing username and password File format: <username>:<realm>:md5(<username>:<realm>:<password>)\n Generate digest file using Apache: htdigest [-c] passwordfile realm username Security note: the <password> is encrypted but MD5 is NOT considered anymore a secure way to store password (GPU brute force attacks).
Digest Apache resolver Generate Apache credential file using htpasswd: htpasswd -c passwordfile username Security note: the <password> is encrypted using MD5, CRYPT or SHA. The SHA algorithm does not use a salt and is less secure than the MD5 algorithm. Even these algorithms are NOT considered anymore a secure way to store password (GPU brute force attacks).
OAuth2 OAuth2 (RFC 6749) is an Authotization Framework that can be used to implement different use cases It uses an authentication mechanism based on username, password or client_id, client_credential to generate a random token (with a lifetime) The token is used as authorization mechanism for client to server communications. Header example: Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia Security note: OAuth2 MUST be used with TSL/SSL to be considered secure!
OAuth2 definitions Resource Owner: the User Resource Server: the API Authorization Server: often the same as the API server Client: the Third-party Application
OAuth2 auth. use cases OAuth2 can be used in different authentication use cases: Web server applications Browser-based applications (e.g. SPA) Mobile applications Username/password Application access
OAuth2 web server app. 3 steps authentication: A Login link to the OAuth2 server with client_id, redirect_uri and scope Authorization page (Allow, Deny buttons). If the user clicks "Allow," the service redirects the user back to server site with an authorization code The application send the authorization code to the OAuth2 server and get the access token Security note: the service should require apps to preregister their redirect URIs
OAuth2 browser-based app 2 steps authentication: A Login link to the OAuth2 server with client_id, redirect_uri and scope An authorization page (Allow, Deny buttons). If the user clicks "Allow," the service redirects the user back to the app. site with an access token, using a fragment #, for instance: https://<oauth2client>/cb#token=access_token There's no other steps! A Javascript code can pull out the access token from the fragment (the part after the #) and begin making API requests
OAuth2 mobile app 2 steps authentication: A Login link to the native app of the service on the phone, or a mobile web page for the service. Example: on iphone, apps can register a custom URI protocol such as "facebook://". On Android, apps can register URL matching patterns which will launch the native app if a URL matching the pattern is visited. If the user clicks "Allow,", the user will be redirected back to the application with the token. The mobile app can parse out the access token from the URI and use it to make API requests.
OAuth2 username and password 1 step authentication: The application sent a request with username and password to the OAuth2 server send the token as response. This scenario is quite common in web application with a Login page. Security note: The username and password auth. is only appropriate for trusted clients, most likely firstparty apps only. If you build your own website as a client of your API, thenk this is a great way to handle loggin in.
OAuth2 application access 1 step authentication: The application sent a request with client_id and client_secret to the OAuth2 server send the token as response. Instead of user's credential we are authenticate client application Useful for API machine to machine
Apigility and OAuth2 security Apigility stores all the OAuth2 information in a PDO database (SQLite by default) All the sensitive data such as client_secret, password, are encrypted using the bcrypt algorithm Security note: remember to use OAuth2 only with TLS/SSL (https)
Apigility implementation details Authentication and Authorization: https://github.com/zfcampus/zf-mvc-auth HTTP Basic/Digest authentication: Zend\Authentication\Adapter\Http https://github.com/zendframework/zf2 OAuth2 server: https://github.com/zfcampus/zf-oauth2 That uses the oauth2-server-php project by Brent Shaffer
Custom API authentication You can implement your API authentication mechanism overwriting the "authentication" ZF2 service generated by zf-mvc-auth: https://github.com/zfcampus/zf-mvc-auth Another possibility is to register a listener on the "authenticate" event at priority > 1. If you return a ZF\MvcAuth\Identity\IdentityInterface implementation or Zend\Authentication\Result from your listener, the default listener will be bypassed
Demo username, password /api/user Authorization: Bearer xxxxx 3 1 OAuth2 token 2
Thanks! More information: http://www.apigility.org