Check session status
Ory stores session data in different ways for browser apps and native apps:
- For browser apps, Ory stores session data in Ory Session Cookies
- For native apps, Ory stores session data in Ory Session Tokens
Refresh your knowledge on the cookie-based security used by Ory and the difference between browser and native APIs.
To check if the user is signed in and has an active session, use the /sessions/whoami
endpoint. If the user doesn't have an
active session, the system returns a 401 Unauthorized
response. If the user has an active session, you get a 200 OK
response
and the session payload.
When using the SDK, use the frontend.toSession()
method.
- cURL
- AJAX / SPA
- ExpressJS
- Go
- React Native
To check for an active session with an Ory Session Token, run:
curl -H "Authorization: Bearer {your-session-token}" \
"https://{project.slug}.projects.oryapis.com/sessions/whoami"
To check for an active session with an Ory Session Cookie, run:
curl -H "Cookie: ory_session_...=..." \
"https://{project.slug}.projects.oryapis.com/sessions/whoami"
When calling Ory or your API from a Single Page Application (SPA) using AJAX:
- The SPA (
www.yourdomain.com
,localhost:3000
), Ory (ory.yourdomain.com
,localhost:4000
), and your API must be on the same domain. - You configured CORS in the Ory Console and on your API server.
- The cookie is configured to be available on the domains you need, for example, the full
yourdomain.com
.
const { FrontendApi, Configuration } = require("@ory/client")
const ory = new FrontendApi(
new Configuration({
basePath: `{YOUR-CUSTOM-DOMAIN-OR-ORY-TUNNEL}`,
baseOptions: {
withCredentials: true,
},
}),
)
const session = await ory.toSession().catch((err) => {
// Check the error to see if it's a 401 / 403 -> not logged in
})
Ory checks for both the cookie and the token, which means that your API must handle both Ory Session Cookies and Ory Session Tokens:
const express = require("express")
const app = express()
const { FrontendApi, Configuration } = require("@ory/client")
const ory = new FrontendApi(
new Configuration({
basePath: `https://${process.env.PROJECT_SLUG}.projects.oryapis.com`,
}),
)
app.get("/blog/posts", async function (req, res) {
const authHeader = req.headers.authorization
const hasAuthHeader = authHeader.startsWith("Bearer ")
const sessionToken = hasAuthHeader
? authHeader.slice(7, authHeader.length)
: null
const session = await ory
.toSession({
cookie: req.cookies.join("; "),
xSessionToken: sessionToken,
})
.catch((err) => {
// Check the error to see if it's a 401 / 403 -> not logged in
})
})
app.listen(3000, function () {
console.log("Listening on http://localhost:3000")
})
Ory checks for both the cookie and the token, which means that your API must handle both Ory Session Cookies and Ory Session Tokens:
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
)
import "github.com/ory/client-go"
var ory *client.APIClient
func init() {
conf := client.NewConfiguration()
conf.Servers = client.ServerConfigurations{{URL: "https://" + os.Getenv("ORY_PROJECT_SLUG") + ".projects.oryapis.com"}}
ory = client.NewAPIClient(conf)
}
func main() {
fmt.Println("Listening on :3000")
err := http.ListenAndServe(":3000", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := ""
if h := r.Header.Get("Authorization"); strings.HasPrefix(strings.ToLower(h), "bearer ") {
token = h[7:]
}
cookies := r.Header.Values("Cookie")
session, _, err := ory.FrontendApi.ToSession(context.Background()).
XSessionToken(token).
Cookie(strings.Join(cookies, "; ")).
Execute()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(session)
}))
if err != nil {
panic(err)
}
}
import { Configuration, FrontendApi, Session } from "@ory/client"
import { useEffect, useState } from "react"
import * as SecureStore from "expo-secure-store"
const ory = new FrontendApi(
new Configuration({
basePath: `https://{project.slug}.projects.oryapis.com`,
}),
)
async function getSessionTokenFromStore() {
return await SecureStore.getItemAsync("session_token")
}
export default async function SomeComponent() {
const [session, setSession] = useState<Session | undefined>()
const sessionToken = await getSessionTokenFromStore()
useEffect(() => {
if (!sessionToken) {
return
}
ory
.toSession({
xSessionToken: sessionToken,
})
.then(({ data }) => setSession(data))
}, [sessionToken])
return <div>{session?.id}</div>
}
Session response
Ory sessions have the format of:
{
"id": "65dea6f4-5d15-4e61-9eb7-f30190c0b2e2",
"active": true,
"expires_at": "2022-12-31T13:50:30.427292Z",
"authenticated_at": "2022-12-01T13:50:30.825516Z",
"authenticator_assurance_level": "aal1",
"authentication_methods": [
{
"method": "password",
"aal": "aal1",
"completed_at": "2022-12-01T13:50:30.427375604Z"
}
],
"issued_at": "2022-12-01T13:50:30.427292Z",
"identity": {
"id": "969d7a6e-b8a9-49ea-bf7b-9e2732a41a81",
"schema_id": "9cadbdf1d6bc5c5c521a1c17ea83648c911c5cd74a14d9e6cc11a5790d133339c3524f8a2d35d34f4151d2df10a7b73d19f7bd0f709fd5ace9019e080bbc4df6",
"state": "active",
"state_changed_at": "2022-12-01T13:50:30.331786Z",
"traits": {
"consent": {
"newsletter": false,
"tos": "2022-12-01T13:50:28.706Z"
},
"email": "user@example.org",
"name": "User"
},
"verifiable_addresses": [
{
"id": "f5f4afde-697e-4e10-a6b6-f870dce927d6",
"value": "user@example.org",
"verified": false,
"via": "email",
"status": "sent",
"created_at": "2022-12-01T13:50:30.345386Z",
"updated_at": "2022-12-01T13:50:30.345386Z"
}
],
"recovery_addresses": [
{
"id": "6e16a3b4-518f-4a5a-b045-95177deb40f1",
"value": "user@example.org",
"via": "email",
"created_at": "2022-12-01T13:50:30.35227Z",
"updated_at": "2022-12-01T13:50:30.35227Z"
}
],
"metadata_public": null,
"created_at": "2022-12-01T13:50:30.340643Z",
"updated_at": "2022-12-01T13:50:30.340643Z"
},
"devices": [
{
"id": "592515ee-7b70-4e08-b4d7-fb0b1643cb48",
"ip_address": "2001:a61:1101:8001:cc85:1111:2222:3333",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
"location": "Berlin, DE"
}
]
}