Skip to content

Commit

Permalink
Get token with OAuth
Browse files Browse the repository at this point in the history
  • Loading branch information
albertolerda committed Oct 28, 2024
1 parent c25103a commit 8cb4f41
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 0 deletions.
9 changes: 9 additions & 0 deletions oauth-intro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# oauth-intro
### _Your Name <[email protected]>_

This is a project to do ... something.

## License

Specify license here

86 changes: 86 additions & 0 deletions oauth-intro/docker-compose/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---

services:
postgresql:
image: docker.io/library/postgres:16-alpine
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
start_period: 20s
interval: 30s
retries: 5
timeout: 5s
volumes:
- database:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
POSTGRES_USER: ${PG_USER:-authentik}
POSTGRES_DB: ${PG_DB:-authentik}
env_file:
- .env
redis:
image: docker.io/library/redis:alpine
command: --save 60 1 --loglevel warning
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 20s
interval: 30s
retries: 5
timeout: 3s
volumes:
- redis:/data
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.3}
restart: unless-stopped
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
volumes:
- ./media:/media
- ./custom-templates:/templates
env_file:
- .env
ports:
- "${COMPOSE_PORT_HTTP:-9000}:9000"
- "${COMPOSE_PORT_HTTPS:-9443}:9443"
depends_on:
- postgresql
- redis
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.8.3}
restart: unless-stopped
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgresql
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
# `user: root` and the docker socket volume are optional.
# See more for the docker socket integration here:
# https://goauthentik.io/docs/outposts/integrations/docker
# Removing `user: root` also prevents the worker from fixing the permissions
# on the mounted folders, so when removing this make sure the folders have the correct UID/GID
# (1000:1000 by default)
user: root
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./media:/media
- ./certs:/certs
- ./custom-templates:/templates
env_file:
- .env
depends_on:
- postgresql
- redis

volumes:
database:
driver: local
redis:
driver: local
11 changes: 11 additions & 0 deletions oauth-intro/oauth-intro.asd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
;;;; oauth-intro.asd

(asdf:defsystem #:oauth-intro
:description "Describe oauth-intro here"
:author "Your Name <[email protected]>"
:license "Specify license here"
:version "0.0.1"
:serial t
:depends-on (#:ningle #:clack #:spinneret #:ironclad #:qbase64 #:dexador)
:components ((:file "package")
(:file "oauth-intro")))
121 changes: 121 additions & 0 deletions oauth-intro/oauth-intro.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
;;;; oauth-intro.lisp

(in-package #:oauth-intro)

(defvar *app* (make-instance 'ningle:app))
(defvar *authorize-uri* "http://localhost:9000/application/o/authorize/")
(defvar *token-uri* "http://localhost:9000/application/o/token/")
(defvar *client-id* "...")
(defvar *client-secret* "...")
(defvar *redirect-uri* "http://localhost:5000/oauth-callback")

(defmacro from-session (key)
`(gethash ,key
(getf (lack.request:request-env ningle:*request*)
:lack.session)))

(defmacro main-layout (&body body)
`(spinneret:with-html-string
(:doctype)
(:html
(:head
(:meta :charset "utf-8")
(:meta :name "viewport" :content "width=device-width, initial-scale=1")
(:script :src "https://unpkg.com/[email protected]")
(:link :rel "stylesheet" :href "https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css"))
(:body
(:section :class "section"
,@body)))))




(defun base64-url-encode (bytes)
(let* ((base64-str (qbase64:encode-bytes bytes))
(url-safe-str (substitute #\- #\+ (substitute #\_ #\/ base64-str))))
(string-right-trim "=" url-safe-str)))


(defun generate-and-save-state ()
(let ((state (base64-url-encode
(ironclad:random-data 64))))
(setf (from-session :oauth-state) state)
state))

(defun generate-and-save-nonce ()
(let ((nonce (base64-url-encode
(ironclad:random-data 64))))
(setf (from-session :oauth-nonce) nonce)
nonce))

(defun sha256 (bytes)
(let ((digester (ironclad:make-digest :sha256)))
(ironclad:update-digest digester bytes)
(ironclad:produce-digest digester)))


(defun generate-and-save-challenge ()
(let ((code-verifier (base64-url-encode (ironclad:random-data 64))))
(setf (from-session :oauth-code) code-verifier)
(base64-url-encode
(sha256 (flexi-streams:string-to-octets code-verifier)))))






(setf (ningle:route *app* "/login")
#'(lambda (params)
(declare (ignore params))
(let* ((state (generate-and-save-state))
(code-challenge (generate-and-save-challenge))
(nonce (generate-and-save-nonce))
(final-uri (concatenate 'string
*authorize-uri* "?"
"client_id=" *client-id* "&"
"redirect_uri=" *redirect-uri* "&"
"state=" state "&"
"response_type=code" "&"
"code_challenge=" code-challenge "&"
"code_challenge_method=S256" "&"
"nonce=" nonce "&"
)))
`(301 (:location ,final-uri)))))


(setf (ningle:route *app* "/oauth-callback")
#'(lambda (params)
(let ((code (cdr (assoc "code" params :test #'string=)))
(state (cdr (assoc "state" params :test #'string=)))
(state-req (from-session :oauth-state))
(code-verifier-req (from-session :oauth-code))
(nonce-req (from-session :oauth-nonce)))

(if (string/= state-req state)
`(302 (:location "/"))
(let ((token
(dex:post *token-uri*
:verbose t
:headers
'(("Content-Type" . "application/x-www-form-urlencoded"))
:content
`(("client_id" . ,*client-id*)
("client_secret" . ,*client-secret*)
("code" . ,code)
("code_verifier" . ,code-verifier-req)
("grant_type" . "authorization_code")
("redirect_uri" . ,*redirect-uri*)))))
`(200 (:content-type "application/json") (,token)))))))


(setf (ningle:route *app* "/")
#'(lambda (params)
(declare (ignore params))
(main-layout
(:a :href "/login" "Login"))))

(clack:clackup
(lack.builder:builder
(:session)
*app*))
4 changes: 4 additions & 0 deletions oauth-intro/package.lisp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
;;;; package.lisp

(defpackage #:oauth-intro
(:use #:cl))

0 comments on commit 8cb4f41

Please sign in to comment.