Svelte | Auth0 と連携した認証

ここ( Svelte Auth0 integration in 66 LOC)を参考に Svelte で Auth0 を使った認証を試してみました。

参考 URL のコードをまんまコピーしただけ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import {onMount, setContext, getContext} from 'svelte';
import {writable} from 'svelte/store';
import createAuth0Client from '@auth0/auth0-spa-js';

const isLoading = writable(true);
const isAuthenticated = writable(false);
const authToken = writable('');
const userInfo = writable({});
const authError = writable(null);
const AUTH_KEY = {};

// Default Auth0 expiration time is 10 hours or something like that.
// If you want to get fancy you can parse the JWT token and get
// token's actual expiration time.
const refreshRate = 10 * 60 * 60 * 1000;

function createAuth(config) {
let auth0 = null;
let intervalId = undefined;

// You can use Svelte's hooks in plain JS files. How nice!
onMount(async () => {
auth0 = await createAuth0Client(config);

// Not all browsers support this, please program defensively!
const params = new URLSearchParams(window.location.search);

// Check if something went wrong during login redirect
// and extract the error message
if (params.has('error')) {
authError.set(new Error(params.get('error_description')));
}

// if code then login success
if (params.has('code')) {
// Let the Auth0 SDK do it's stuff - save some state, etc.
await auth0.handleRedirectCallback();
// Can be smart here and redirect to original path instead of root
window.history.replaceState({}, document.title, '/');
authError.set(null);
}

const _isAuthenticated = await auth0.isAuthenticated();
isAuthenticated.set(_isAuthenticated);

if (_isAuthenticated) {
// while on it, fetch the user info
userInfo.set(await auth0.getUser());

// Get the access token. Make sure to supply audience property
// in Auth0 config, otherwise you will soon start throwing stuff!
const token = await auth0.getTokenSilently();
authToken.set(token);

// refresh token after specific period or things will stop
// working. Useful for long-lived apps like dashboards.
intervalId = setInterval(async () => {
authToken.set(await auth0.getTokenSilently());
}, refreshRate);
}
isLoading.set(false);

// clear token refresh interval on component unmount
return () => {
intervalId && clearInterval(intervalId);
};
});

// Provide a redirect page if you need.
// It must be whitelisted in Auth0. I think.
const login = async redirectPage => {
await auth0.loginWithRedirect({
redirect_uri: redirectPage || window.location.origin,
prompt: 'login' // Force login prompt. No silence auth for you!
});
};

const logout = () => {
auth0.logout({
returnTo: window.location.origin
});
};

const auth = {
isLoading,
isAuthenticated,
authToken,
authError,
login,
logout,
userInfo
};

// Put everything in context so that child
// components can access the state
setContext(AUTH_KEY, auth);

return auth;
}

// helper function for child components
// to access the auth context
function getAuth() {
return getContext(AUTH_KEY);
}

export {createAuth, getAuth};
[code]

### src/App.svelte

```HTML
<script>
import { createAuth } from './auth';

// Go to Auth0 to get the values and set everything up.
// Make sure all callback urls are set correctly.
const config = {
domain: 'Auth0で作成したドメイン',
client_id: 'Auth0で生成されたclient_id',
//audience: 'https://my-facebook-killer.io'
};

const {
isLoading,
isAuthenticated,
login,
logout,
authToken,
authError,
userInfo
} = createAuth(config);

$: state = {
isLoading: $isLoading,
isAuthenticated: $isAuthenticated,
authError: $authError,
userInfo: $userInfo ? $userInfo.name : null,
authToken: $authToken.slice(0, 20)
};
</script>

<style>
main {
padding: 1em;
max-width: 240px;
margin: 0 auto;
}

@media (min-width: 640px) {
main {
max-width: none;
}
}
</style>

<div>
<div>
{#if $isAuthenticated}
<button on:click={() => logout()}>Logout</button>
{:else}
<button on:click={() => login()}>Login</button>
{/if}
</div>

<h2>State</h2>
<pre>{JSON.stringify(state, null, 2)}</pre>
</div>

認証できることは確認したので、実際になにか Web サービスに組み込んでみたい。